Objective
This project aims to develop a bankruptcy prediction model using
Support Vector Machines (SVM) and Regularized Regression techniques in
R. By leveraging historical financial data, the model will classify
companies based on their likelihood of bankruptcy. The objective is to
compare the performance of SVM and regularized regression methods in
terms of predictive accuracy, interpretability, and robustness.
Additionally, the project seeks to identify key financial indicators
that contribute to bankruptcy risk, providing insights for financial
analysts and decision-makers.
Introduction
Description of data:
- Bankrupt (int, target variable) – Indicates whether
a company has gone bankrupt (0 = No, 1 = Yes).
- Current_Ratio (float) – Measures a company’s
ability to pay short-term obligations (current assets / current
liabilities).
- Quick_Ratio (float) – A liquidity metric that
excludes inventory from current assets (quick assets / current
liabilities).
- Total_debt_by_Total_networth (float) – Represents
the company’s total debt in proportion to its net worth.
- Debt_ratio_Percent (float) – The percentage of a
company’s assets financed by debt (total debt / total assets *
100).
- Operating_profit_by_Paidin_capital (float) –
Measures profitability in relation to paid-in capital.
- Total_Asset_Turnover (float) – Indicates how
efficiently a company utilizes its assets to generate sales.
- Working_Capital_to_Total_Assets (float) –
Proportion of working capital in total assets, reflecting
liquidity.
- Cash_Flow_to_Total_Assets (float) – Measures how
much cash flow a company generates relative to its total assets.
- Cash_Flow_to_Liability (float) – Represents the
proportion of cash flow available to cover liabilities.
- Current_Liability_to_Current_Assets (float) – Ratio
of current liabilities to current assets, indicating liquidity
risk.
- Gross_Profit_to_Sales (float) – Percentage of gross
profit generated from total sales (gross profit / sales).
- Leverage_SD (categorical) – Categorized as “Low,”
“Moderate,” or other levels, representing the company’s leverage
risk.
Relationship between Features
Correlation Plot
The correlation matrix heatmap visually represents the relationships
between financial variables and bankruptcy status. Notable insights
include a negative correlation between Current Ratio
and Bankruptcy (-0.32), indicating that companies with
lower liquidity are more likely to go bankrupt. Total debt to
Total net worth (0.38) and Debt Ratio Percent
(0.22) show positive correlations with bankruptcy, suggesting
higher leverage increases bankruptcy risk. A strong positive correlation
(0.87) exists between Cash Flow to
Liability and Cash Flow to Total Assets, while
Current Ratio and Quick Ratio are also
highly correlated (0.76), reflecting interdependencies
among liquidity metrics. These insights can aid in financial risk
assessment and bankruptcy prediction modeling.
df_num <- df
df_num$Bankrupt <- as.numeric(as.factor(df_num$Bankrupt))
numeric_features <- df_num %>% select_if(is.numeric)
# Compute correlation matrix
cor_matrix <- cor(numeric_features, use = "complete.obs")
# Plot heatmap
ggcorrplot(cor_matrix, method = "circle", type = "lower", lab = TRUE)

Relationship between Features
Relationship between highly correlated numerical features
using Scatter Plot
The scatter plot of Cash Flow to Total Assets (CF/TA) vs. Cash Flow
to Liabilities (CF/L) reveals a strong positive correlation, indicating
that firms generating higher cash flow relative to their assets also
tend to have higher cash flow relative to their liabilities. The
majority of data points cluster along a linear trend, suggesting a
consistent relationship between asset utilization and liability
coverage. A few outliers above the main cluster suggest firms with
exceptionally strong cash flow management or low liabilities, while
those below the trend may indicate companies struggling with debt
repayment. This analysis highlights the overall financial efficiency and
potential risk factors within the dataset.
# Scatter plot using ggplot2
ggplot(df, aes(x=Cash_Flow_to_Total_Assets, y=Cash_Flow_to_Liability)) +
geom_point(color="blue", alpha=0.5) +
ggtitle(" Cash Flow to Total Assets vs Cash Flow to Liability") +
xlab("Cash Flow to Total Assets ") +
ylab("Cash Flow to Liability")

Relationship between Target Variable(Bankrupt) and a
categorical feature using heatmap
The heatmap illustrates the relationship between leverage
level (Total Debt to Total Net Worth) and bankruptcy status.
The majority of firms classified under the “Moderate” leverage
category are non-bankrupt (deep blue), while a smaller portion
within this category has gone bankrupt (lighter purple). There are no
firms categorized under “High” leverage, which might
suggest data imbalance or absence of high-leverage firms in the dataset.
This visualization highlights that companies with moderate leverage are
more prevalent, but some still face bankruptcy risks.
df$Bankrupt <- as.factor(df$Bankrupt)
heatmap_data <- df %>%
count(Bankrupt, Leverage_SD)
# Heatmap: Relationship between Default and Employment Status
ggplot(heatmap_data, aes(x = Bankrupt, y = Leverage_SD , fill = n)) +
geom_tile() +
labs(title = "Heatmap: Bankrupt vs Leverage Level (Total Debt to Total Net Worth)",
x = "Bankrupt", y = "Leverage_SD") +
scale_fill_gradient(low = "white", high = "blue") +
theme_minimal()

Box Plot
The box plot compares the Current Ratio between
bankrupt and non-bankrupt firms. Non-bankrupt firms (teal) tend to have
a higher median current ratio compared to bankrupt firms (yellow),
indicating better liquidity. The interquartile range (IQR) for
non-bankrupt firms is wider, suggesting more variation in liquidity
levels. Bankrupt firms have a lower median current ratio, with a more
compressed distribution, showing that lower liquidity is associated with
financial distress. Additionally, both groups have outliers, but the
non-bankrupt firms exhibit a greater range of higher current ratios.
# Box Plot: Relationship between Bankrupt (Categorical) and Current Ratio (Numerical)
ggplot(df, aes(x = Bankrupt, y = Current_Ratio, fill = Bankrupt)) +
geom_boxplot() +
labs(title = "Box Plot: Bankrupt vs Current Ratio",
x = "Bankrupt Status", y = "Current Ratio") +
theme_minimal() +
scale_fill_brewer(palette = "Set3")

Skewness
The skewness analysis reveals that several financial variables
exhibit significant skewness, indicating asymmetric distributions.
Highly skewed variables include Quick Ratio,
Total Debt to Total Net Worth, Debt Ratio Percent, Operating Profit by
Paid-in Capital, Total Asset Turnover, Working Capital to Total Assets,
Cash Flow to Total Assets, Cash Flow to Liability, Current Liability to
Current Assets, and Gross Profit to Sales. Notably,
Cash Flow to Liability (-9.58) and Total Debt
to Total Net Worth (16.23) have extreme skewness values,
suggesting a strong deviation from normality. These findings indicate
potential data transformations may be necessary for statistical
modeling.
# Select only numeric columns
numeric_vars <- df[, sapply(df, is.numeric)]
# Compute skewness for each numeric variable
skewness_values <- sapply(numeric_vars, skewness, na.rm = TRUE)
# Identify highly skewed variables
skewed_vars <- names(skewness_values[abs(skewness_values) > 1])
# Print results
#print("Skewness values:")
#print(skewness_values)
print("Highly skewed variables:")
[1] "Highly skewed variables:"
print(skewed_vars)
[1] "Quick_Ratio" "Total_debt_by_Total_networth"
[3] "Debt_ratio_Percent" "Operating_profit_by_Paidin_capital"
[5] "Total_Asset_Turnover" "Working_Capital_to_Total_Assets"
[7] "Cash_Flow_to_Total_Assets" "Cash_Flow_to_Liability"
[9] "Current_Liability_to_Current_Assets" "Gross_Profit_to_Sales"
# Create a histogram for Skewed Numeric Variable - No of Credit Accounts
#hist(numeric_vars$No_of_credit_acc, main = "Histogram of No of Credit Accounts", xlab = "No of Credit Accounts", col = "lightblue", breaks = 30)
Principal Component Analysis
The Principal Component Analysis (PCA) results indicate that the
first few principal components capture most of the variance in the
dataset, with PC1 alone explaining 27.7% and the first five components
accounting for approximately 70.7% of the total variance. The scree plot
further confirms that beyond a certain number of components, the
variance explained drops significantly, suggesting that dimensionality
reduction is feasible. The scatter plot of the first two principal
components shows some clustering but also highlights outliers that may
influence the analysis. Overall, applying PCA in this project is
beneficial as it helps reduce dimensionality while retaining most of the
important information, improving model efficiency and interpretability,
especially when dealing with highly correlated and skewed variables.
# Step 1: Convert categorical variables to numeric using one-hot encoding
df_numeric <- df %>%
mutate(across(c(Bankrupt, Leverage_SD), as.factor)) %>% # Convert to factors
dummyVars(~ ., data = .) %>%
predict(newdata = df) %>%
as.data.frame()
# Step 2: Select only numeric features
numeric_data <- df_numeric %>% select_if(is.numeric)
# Step 3: Handle missing and infinite values
numeric_data[is.na(numeric_data)] <- 0 # Replace NAs with 0 (or use median imputation)
constant_cols <- apply(numeric_data, 2, function(col) var(col, na.rm = TRUE) == 0)
numeric_data <- numeric_data[, !constant_cols]
# Step 4: Standardize the data (only after handling missing values)
scaled_data <- scale(numeric_data)
# Step 5: Perform PCA
pca_result <- prcomp(scaled_data, center = TRUE, scale = TRUE)
summary(pca_result)
Importance of components:
PC1 PC2 PC3 PC4 PC5 PC6 PC7
Standard deviation 2.0387 1.4023 1.3164 1.2205 1.12261 1.03752 0.97403
Proportion of Variance 0.2771 0.1311 0.1155 0.0993 0.08402 0.07176 0.06325
Cumulative Proportion 0.2771 0.4082 0.5237 0.6230 0.70702 0.77879 0.84204
PC8 PC9 PC10 PC11 PC12 PC13 PC14
Standard deviation 0.8068 0.72611 0.66834 0.63905 0.4549 0.35950 1.357e-14
Proportion of Variance 0.0434 0.03515 0.02978 0.02723 0.0138 0.00862 0.000e+00
Cumulative Proportion 0.8854 0.92058 0.95036 0.97759 0.9914 1.00000 1.000e+00
PC15
Standard deviation 4.693e-17
Proportion of Variance 0.000e+00
Cumulative Proportion 1.000e+00
# Step 6: Scree Plot (to decide number of components to keep)
screeplot(pca_result, type = "lines", main = "Scree Plot")

# Step 7: Biplot (PCA visualization)
# biplot(pca_result, scale = 0)
# Step 8: Scatter plot of first two principal components
pca_df <- as.data.frame(pca_result$x)
ggplot(pca_df, aes(x = PC1, y = PC2)) +
geom_point(size = 3, alpha = 0.7, color = "blue") +
labs(title = "PCA - First Two Principal Components") +
theme_minimal()

Regularization
- Regularized Logistic Regression:
The results from the LASSO regularized regression analysis provide
key insights into feature selection and model performance.
Coefficient Path Plot (Left Panel): This plot shows how the
regression coefficients shrink as the regularization parameter (λ)
increases. Initially, at low λ values (right side of the plot), most
predictors have nonzero coefficients, meaning they are actively
contributing to the model. As λ increases (moving left), many
coefficients shrink toward zero, demonstrating LASSO’s ability to
enforce sparsity by selecting only the most important features. The red
dashed line represents the λ value that minimizes cross-validation
error, striking a balance between model complexity and predictive power.
The blue dashed line represents the most regularized model within one
standard error of the minimum cross-validation error, often chosen for
better generalization.
Model Fit Plot (Right Panel): This plot illustrates the binomial
deviance (a measure of model error) for different λ values. The curve
initially decreases, indicating that moderate regularization improves
model performance by reducing overfitting. The red points represent mean
deviance values, with error bars showing variability. The deviance
reaches its lowest point around λ≈−5 (log scale), after which it
increases as excessive regularization removes too many important
features, leading to underfitting.
df <- df_stan
# Split the data into predictors (X) and response (y)
X <- model.matrix(Bankrupt ~ ., df_stan)[,-1] # Remove the intercept column
y <- df$Bankrupt
# Split the data into training and testing sets
set.seed(123)
trainIndex <- createDataPartition(y, p = 0.8, list = FALSE)
X_train <- X[trainIndex, ]
X_test <- X[-trainIndex, ]
y_train <- y[trainIndex]
y_test <- y[-trainIndex]
#table(y_test)
####################
# Fit LASSO model
####################
lasso_model <- glmnet(X_train, y_train, family = "binomial", alpha = 1)
# Cross-validation to find the optimal lambda
cv_lasso <- cv.glmnet(X_train, y_train, family = "binomial", alpha = 1)
# Optimal lambda
lambda_lasso <- cv_lasso$lambda.min
# Refit the model with the optimal lambda
lasso_model_opt <- glmnet(X_train, y_train,
family = "binomial",
alpha = 1,
lambda = lambda_lasso)
## Visualize the impact of lambda on shrinking coefficients
# Plot coefficient paths
par(mar=c(5,4,6,2), mfrow=c(1,2)) #
plot(lasso_model, xvar = "lambda", label = TRUE,
col = rainbow(8),
lwd = 1,
main = "Coefficient Path Plot: LASSO",
cex.main = 0.8)
text(-6, 0.4, "minimum CV error", col="red", cex = 0.6 )
abline(v = log(cv_lasso$lambda.min), col = "red", lty = 4, lwd = 1)
abline(v = log(cv_lasso$lambda.1se), col = "blue", lty = 4, lwd = 1)
plot(cv_lasso, main="Measure of Model Fit: LASSO", cex.main = 0.8)

####################
# Fit Ridge model
####################
ridge_model <- glmnet(X_train, y_train, family = "binomial", alpha = 0)
# Cross-validation to find the optimal lambda
cv_ridge <- cv.glmnet(X_train, y_train, family = "binomial", alpha = 0)
# Optimal lambda
lambda_ridge <- cv_ridge$lambda.min
# Refit the model with the optimal lambda
ridge_model_opt <- glmnet(X_train, y_train,
family = "binomial",
alpha = 0,
lambda = lambda_ridge)
############################################
# Fit Elastic Net model (e.g., alpha = 0.5)
############################################
elastic_model <- glmnet(X_train, y_train, family = "binomial", alpha = 0.5)
# Cross-validation to find the optimal lambda
cv_elastic <- cv.glmnet(X_train, y_train, family = "binomial", alpha = 0.5)
# Optimal lambda
lambda_elastic <- cv_elastic$lambda.min
# Refit the model with the optimal lambda
elastic_model_opt <- glmnet(X_train, y_train,
family = "binomial",
alpha = 0.5,
lambda = lambda_elastic)
lasso.coef <- as.matrix(coef(lasso_model_opt))
ridge.coef <- as.matrix(coef(ridge_model_opt))
elastic.coef <- as.matrix(coef(elastic_model_opt))
regularized.coef <- data.frame(lasso = lasso.coef[,1],
ridge = ridge.coef[,1],
elasticnet = elastic.coef[,1])
pander(regularized.coef)
| (Intercept) |
-1.591 |
-0.3881 |
-1.548 |
| Leverage_SD |
0 |
-0.5822 |
0 |
| Current_Ratio_stand |
-0.3381 |
-0.4755 |
-0.3579 |
| Quick_Ratio_stand |
0 |
-0.02971 |
0 |
| Total_debt_by_Total_networth_stand |
0 |
0.286 |
0.00328 |
| Operating_profit_by_Paidin_capital_stand |
-0.8337 |
-0.6194 |
-0.6786 |
| Total_Asset_Turnover_stand |
-0.1303 |
-0.1888 |
-0.1204 |
| Cash_Flow_to_Total_Assets_stand |
-0.169 |
-0.2153 |
-0.182 |
| Cash_Flow_to_Liability_stand |
-0.09913 |
-0.1134 |
-0.08148 |
| Current_Liability_to_Current_Assets_stand |
0 |
-0.05365 |
0 |
| Gross_Profit_to_Sales_stand |
-0.1333 |
-0.2754 |
-0.1738 |
| Debt_ratio_Percent_stand |
0.9952 |
0.7918 |
0.8882 |
| Working_Capital_to_Total_Assets_stand |
0 |
0.07734 |
0 |
Optimal Cuttoff Probability Determination
Optimal Cutoff Probability for this model is 0 for the reasons
below:
Class Imbalance: A highly imbalanced dataset may cause the model to
favor the majority class, leading to an optimal cut-off of 0 for maximum
accuracy.
Over-Regularization: Strong regularization (high lambda values) can
shrink coefficients, reducing the model’s ability to differentiate
between classes.
Bias in Probability Estimates: If predicted probabilities are skewed
toward higher values, the model may classify most instances as the
positive class, making 0 the best cut-off.
Accuracy as a Misleading Metric: Since accuracy does not account for
class distribution, alternative metrics such as AUC-ROC,
precision-recall, and F1-score should be considered for better threshold
selection.
############################
# Predict on the test set: type = "class" uses the default
# cut-off probability to be 0.5.
predict_lasso <- predict(lasso_model_opt, newx = X_test, type = "response")
predict_ridge <- predict(ridge_model_opt, newx = X_test, type = "response")
predict_elastic <- predict(elastic_model_opt, newx = X_test, type = "response")
###########################################
## Optimal cutoff probability determination
seq.cut <- seq(0,1, length=50)
# y is a vector of 0 and 1
acc.lasso <- NULL
acc.ridge <- NULL
acc.elastic <- NULL
for (i in 1:length(seq.cut)){
predy.lasso <- ifelse(predict_lasso >seq.cut[i], 1, 0)
predy.ridge<- ifelse(predict_ridge >seq.cut[i], 1, 0)
predy.elastic<- ifelse(predict_elastic >seq.cut[i], 1, 0)
##
acc.lasso[i] <- mean(y_test == predy.lasso)
acc.ridge[i] <- mean(y_test == predy.ridge)
acc.elastic[i] <- mean(y_test == predy.elastic)
}
## optimal cut-off: if the maximum accuracy occurs at multiple
## cut-off probabilities, the average of these cutoff probabilities
## will be defined as the optimal cutoff probability
opt.cut.lasso <- mean(seq.cut[which(acc.lasso==max(acc.lasso))])
opt.cut.ridge<- mean(seq.cut[which(acc.ridge==max(acc.ridge))])
opt.cut.elastic <- mean(seq.cut[which(acc.elastic==max(acc.elastic))])
##
# Print optimal cutoff probabilities
#cat("Optimal Cutoff for LASSO:", opt.cut.lasso, "\n")
#cat("Optimal Cutoff for Ridge:", opt.cut.ridge, "\n")
#cat("Optimal Cutoff for Elastic Net:", opt.cut.elastic, "\n")
acc.data <- data.frame(prob = rep(seq.cut,3),
acc=c(acc.lasso, acc.ridge, acc.elastic),
group = c(rep("lasso",50), rep("ridge",50), rep("elastic",50)))
Accuracy Plot
The accuracy vs. cut-off probability plot indicates that all three
models—LASSO, Ridge, and Elastic Net—exhibit nearly identical
classification performance, achieving maximum accuracy (~0.7511) at a
low cut-off threshold. As the cut-off increases, accuracy declines
sharply, suggesting a strong class imbalance or threshold sensitivity.
The models predominantly favor the majority class at lower thresholds,
leading to higher accuracy but potentially poor sensitivity for minority
class detection. The rapid decline in accuracy beyond a 0.1 cut-off
suggests that misclassification rates increase significantly. This
indicates that accuracy alone may not be the best evaluation metric,
warranting additional assessments such as AUC-ROC and F1-score.
Optimizing the threshold using these alternative metrics could enhance
predictive performance.
##
gg.acc <- ggplot(data = acc.data, aes(x=prob, y = acc, color = group)) +
geom_line() +
annotate("text", x = 0.6, y = 0.45,
label = paste( "Accuracy: ", round(max(acc.lasso),5),
"\nAccuracy: ", round(max(acc.ridge),5),
"\nAccuracy: ", round(max(acc.elastic),5)),
size = 3,
color = "navy") +
ggtitle("Cut-off Probability vs Accuracy") +
labs(x = "cut-off Probability",
y = "accuracy", color = "Group") +
theme(plot.title = element_text(hjust = 0.5))
##
ggplotly(gg.acc)
Confusion Matrix
The performance metrics for LASSO, Ridge, and Elastic Net regression
models indicate strong recall (0.9704) across all models, suggesting
that they effectively identify the positive class. However, specificity
is relatively low (0.3929–0.375), meaning the models struggle to
correctly classify negative instances, likely due to class imbalance.
Precision values (~0.82) and F1-scores (~0.89) confirm a good balance
between precision and recall, favoring sensitivity. The balanced
accuracy values (0.6816 for LASSO, 0.6638 for Ridge, and 0.6727 for
Elastic Net) indicate moderate overall performance, with LASSO slightly
outperforming the other models. These results suggest that while the
models are strong in detecting positives, further threshold tuning or
alternative evaluation metrics (such as AUC-ROC) may improve
classification of negative cases.
#######################################
## using the optimal cutoff probability to predict labels
##
#pred.lab.lasso <- ifelse(predict_lasso >opt.cut.lasso, 1, 0)
#pred.lab.ridge<- ifelse(predict_ridge >opt.cut.ridge, 1, 0)
#pred.lab.elastic<- ifelse(predict_elastic >opt.cut.elastic, 1, 0)
new_threshold <- 0.5 # Try adjusting this
pred.lab.lasso <- ifelse(predict_lasso > new_threshold, 1, 0)
pred.lab.ridge<- ifelse(predict_ridge >new_threshold, 1, 0)
pred.lab.elastic<- ifelse(predict_elastic >new_threshold, 1, 0)
#################################
# Convert predictions to factors
pred.lab.lasso.fct <- as.factor(pred.lab.lasso)
pred.lab.ridge.fct <- as.factor(pred.lab.ridge)
pred.lab.elastic.fct <- as.factor(pred.lab.elastic)
y_test <- factor(ifelse(y_test == 2, 1, 0), levels = c(0, 1))
#table(pred.lab.lasso.fct)
#table(y_test)
# Confusion Matrix and Metrics
confusion.lasso <- confusionMatrix(pred.lab.lasso.fct, y_test)
confusion.ridge<- confusionMatrix(pred.lab.ridge.fct, y_test)
confusion.elastic <- confusionMatrix(pred.lab.elastic.fct, y_test)
## Commonly used performance measured
PerfMeasures <- cbind(lasso = confusion.lasso$byClass,
ridge = confusion.ridge$byClass,
elastic = confusion.elastic$byClass)
pander(PerfMeasures)
| Sensitivity |
0.9704 |
0.9704 |
0.9704 |
| Specificity |
0.3929 |
0.3571 |
0.375 |
| Pos Pred Value |
0.8283 |
0.82 |
0.8241 |
| Neg Pred Value |
0.8148 |
0.8 |
0.8077 |
| Precision |
0.8283 |
0.82 |
0.8241 |
| Recall |
0.9704 |
0.9704 |
0.9704 |
| F1 |
0.8937 |
0.8889 |
0.8913 |
| Prevalence |
0.7511 |
0.7511 |
0.7511 |
| Detection Rate |
0.7289 |
0.7289 |
0.7289 |
| Detection Prevalence |
0.88 |
0.8889 |
0.8844 |
| Balanced Accuracy |
0.6816 |
0.6638 |
0.6727 |
ROC Analysis
The ROC curve compares the performance of three logistic regression
models—LASSO, Ridge, and Elastic Net—based on their ability to
distinguish between classes. The area under the curve (AUC) values
indicate that all three models perform similarly, with Elastic Net
achieving the highest AUC (0.841), followed closely by LASSO (0.84) and
Ridge (0.838). These values suggest that the models have good predictive
capabilities, with Elastic Net slightly outperforming the others in
terms of classification accuracy.
# library(pROC)
# Predicted probabilities for each model: type = "response"
prob_lasso <- predict(lasso_model_opt, newx = X_test, type = "response")
prob_ridge <- predict(ridge_model_opt, newx = X_test, type = "response")
prob_elastic <- predict(elastic_model_opt, newx = X_test, type = "response")
# Compute ROC curves: roc object contains a lot information including
# sensitivity, specificity, AUC, etc.
roc_lasso <- roc(y_test, prob_lasso)
roc_ridge <- roc(y_test, prob_ridge)
roc_elastic <- roc(y_test, prob_elastic)
# Compute AUC values
auc_lasso <- auc(roc_lasso)
auc_ridge <- auc(roc_ridge)
auc_elastic <- auc(roc_elastic)
## LASSO
sen.lasso <- roc_lasso$sensitivities
spe.lasso <- roc_lasso$specificities
auc.lasso <- roc_lasso$auc
## Ridge
sen.ridge <- roc_ridge$sensitivities
spe.ridge <- roc_ridge$specificities
auc.ridge <- roc_ridge$auc
## Elastic Net
sen.elastic <- roc_elastic$sensitivities
spe.elastic <- roc_elastic$specificities
auc.elastic <- roc_elastic$auc
## Plotting the ROC curves: three colors - green, orange, and purple
plot(1-spe.lasso, sen.lasso,
type = "l",
col = "green",
xlim=c(0,1),
xlab = "1 - specificity",
ylab = "sensitivity",
main = "ROC Curves for LASSO, Ridge, and Elastic Net")
lines(1-spe.ridge, sen.ridge, col = "orange")
lines(1-spe.elastic, sen.elastic, col = "purple")
abline(0,1, type = "l", lty = 2, col = "steelblue", lwd = 1)
# Add legend
legend("bottomright", legend = c(paste("LASSO (AUC =", round(auc_lasso, 3), ")"),
paste("Ridge (AUC =", round(auc_ridge, 3), ")"),
paste("Elastic Net (AUC =", round(auc_elastic, 3), ")")),
col = c("green", "orange", "purple"), lty = 1, cex = 0.8, bty = "n")

Support Vector Machine for Classification
The results represent a confusion matrix from a Support Vector
Machine (SVM) classification model, where:
- 206 true negatives (correctly classified as class
0)
- 14 false positives (misclassified as class 1 but
actually class 0)
- 58 false negatives (misclassified as class 0 but
actually class 1)
- 61 true positives (correctly classified as class
1)
Analysis:
Accuracy: The model achieves an accuracy of
approximately 78.76%.
Precision (Positive Predictive Value) for Class
1: When the model predicts class 1, it is correct about
81.33% of the time.
Recall (Sensitivity or True Positive Rate) for
Class 1: The model correctly identifies 51.26% of
actual class 1 instances, indicating that it misses a significant number
of positives.
Specificity (True Negative Rate): The model
correctly identifies 93.63% of actual class 0
instances, showing strong performance in recognizing negatives.
Optimal Cutoff: 0.1742
- The classification threshold (cutoff) was optimized to
0.1742, meaning that any predicted probability above
this is classified as class 1.
- A low threshold like this suggests the model is designed to be more
sensitive to detecting class 1, likely to reduce false negatives.
However, this also increases the false positive rate.
The SVM classifier performs well in identifying class 0 (high
specificity) but struggles with class 1 (low recall). The optimal
threshold (0.1742) was chosen to balance sensitivity and specificity,
but the recall for class 1 remains relatively low. If misclassifying
class 1 is costly, adjusting the threshold or model tuning (e.g.,
changing kernel functions, regularization parameters) may improve
recall.
# Load the dataset
df$Bankrupt <- as.factor(df$Bankrupt)
# Train-test split
set.seed(123)
index <- sample(1:nrow(df), 0.7 * nrow(df))
train.data <- df[index, ]
test.data <- df[-index, ]
# Set up custom cross-validation control
tune_control <- tune.control(cross = 5, nrepeat = 1)
# Perform a grid search for the best hyperparameters
tune.RBF <- tune(
svm,
Bankrupt ~ .,
data = train.data,
kernel = "radial",
ranges = list(cost = 10^(-1:2), gamma = c(0.1, 0.5, 1, 2)),
tunecontrol = tune_control
)
# Extract the best model
best.RBF <- tune.RBF$best.model
# Train final model with probability estimation
tuned.svm <- svm(
Bankrupt ~ .,
data = train.data,
kernel = "radial",
cost = best.RBF$cost,
gamma = best.RBF$gamma,
probability = TRUE
)
# Predict probabilities
pred.probs <- predict(tuned.svm, test.data, probability = TRUE)
pred.probs <- attr(pred.probs, "probabilities")[, 2] # Extract probabilities for class "1"
# Compute optimal cutoff by minimizing distance to (0,1) in ROC space
pred <- prediction(pred.probs, test.data$Bankrupt)
perf <- performance(pred, "tpr", "fpr")
cutoffs <- data.frame(
cutoff = perf@alpha.values[[1]],
tpr = perf@y.values[[1]],
fpr = perf@x.values[[1]]
)
cutoffs$distance <- sqrt((1 - cutoffs$tpr)^2 + cutoffs$fpr^2)
optimal.cutoff <- cutoffs$cutoff[which.min(cutoffs$distance)]
# Apply optimal cutoff
pred.optimal.class <- ifelse(pred.probs > optimal.cutoff, 1, 0)
# Confusion matrix with optimal cutoff
confusion.matrix.optimal <- table(Predicted = pred.optimal.class, Actual = test.data$Bankrupt)
print(confusion.matrix.optimal)
Actual
Predicted 1 2
0 206 14
1 58 61
# Print optimal cutoff value
print(paste("Optimal Cutoff: ", optimal.cutoff))
[1] "Optimal Cutoff: 0.17423346704307"
Accuracy
# Calculate accuracy
accuracy <- sum(diag(confusion.matrix.optimal)) / sum(confusion.matrix.optimal)
cat("\n\n Accuracy:", accuracy, "\n")
Accuracy: 0.7876106
ROC
The ROC curve compares the classification performance of three
models: Support Vector Machine (SVM) with a linear kernel, SVM with a
radial kernel, and logistic regression. The Area Under the Curve (AUC)
values indicate that the radial kernel SVM achieves the best performance
(AUC = 0.8756), followed by the linear kernel SVM (AUC = 0.8493), and
logistic regression (AUC = 0.8319). This suggests that the radial kernel
SVM provides the highest discriminatory power in distinguishing between
classes, making it the most effective model for this classification
task.
##
## Set up custom cross-validation control
tune.control <- tune.control(
cross = 5, # Use 5-fold cross-validation, the default is 10-fold cross-validation
nrepeat = 1 # Number of repetitions (for repeated cross-validation)
)
##
## Perform a grid search for the best hyperparameters
tune.lin <- tune(
svm, # using the primary svm() algorithm to tune parameter
Bankrupt ~ ., # model formula
data = train.data,
kernel = "linear", # You can change the kernel if needed
ranges = list(
cost = 10^(-1:2) # tune the hyperparameter C in the loss function
),
tunecontrol = tune.control # Use custom cross-validation settings
)
# Print the tuning results for inspection
# print(tune_result)
##
## Extract the best model and hyperparameters
best.lin <- tune.lin$best.model
best.cost.lin <- best.lin$cost
tune.RBF <- tune(
svm,
Bankrupt ~ .,
data = train.data,
kernel = "radial",
ranges = list(
cost = 10^(-1:2), # Tune cost
gamma = 10^(-3:1) # Tune gamma
),
tunecontrol = tune.control
)
# Extract best hyperparameters
best.cost.RBF <- tune.RBF$best.model$cost
best.gamma.RBF <- tune.RBF$best.model$gamma
# Print the best hyperparameters for inspection
# cat("Best Cost:", best_cost, "\n")
# cat("Best Gamma:", best_gamma, "\n")
##
## Train the final SVM model with the best hyperparameters
final.lin <- svm(
Bankrupt ~ .,
data = train.data,
kernel = "linear",
cost = best.cost.lin,
probability = TRUE
)
## Request to return probabilities in final.RBF
final.RBF <- svm(
Bankrupt ~ .,
data = train.data,
kernel = "radial",
cost = best.cost.RBF,
gamma = best.gamma.RBF,
probability = TRUE
)
########################
### logistic regression
logit.fit <- glm(Bankrupt ~ ., data = train.data, family = binomial)
AIC.logit <- step(logit.fit, direction = "both", trace = 0)
pred.logit <- predict(AIC.logit, test.data, type = "response")
###
####################
# ROC Curve and AUC
pred.prob.lin <- predict(final.lin, test.data, probability = TRUE)
pred.prob.RBF <- predict(final.RBF, test.data, probability = TRUE)
##
## extracting probabilities
prob.linear <- attr(pred.prob.lin, "probabilities")[, 2]
prob.radial <- attr(pred.prob.RBF, "probabilities")[, 2]
###
roc_lin <- roc(test.data$Bankrupt, prob.linear)
roc_RBF <- roc(test.data$Bankrupt, prob.radial)
roc_logit <- roc(test.data$Bankrupt, pred.logit)
### Sen-Spe
lin.sen <- roc_lin$sensitivities
lin.spe <- roc_lin$specificities
rad.sen <- roc_RBF$sensitivities
rad.spe <- roc_RBF$specificities
logit.sen <- roc_logit$sensitivities
logit.spe <- roc_logit$specificities
## AUC
auc.lin <- roc_lin$auc
auc.rad <- roc_RBF$auc
auc.logit <- roc_logit$auc
## Plotting ROC curves
plot(1-lin.spe, lin.sen,
xlab = "1 - specificity",
ylab = "sensitivity",
col = "darkred",
type = "l",
lty = 1,
lwd = 1,
main = "ROC Curves of SVM")
lines(1-rad.spe, rad.sen,
col = "blue",
lty = 1,
lwd = 1)
lines(1-logit.spe, logit.sen,
col = "orange",
lty = 1,
lwd = 1)
abline(0,1, col = "skyblue3", lty = 2, lwd = 2)
abline(v=c(0.049,0.151), lty = 3, col = "darkgreen")
legend("bottomright", c("Linear Kernel", "Radial Kernel", "Logistic Regression"),
lty = c(1,1,1), lwd = rep(1,3),
col = c("red", "blue", "orange"),
bty="n",cex = 0.8)
## annotation - AUC
text(0.8, 0.46, paste("Linear AUC: ", round(auc.lin,4)), cex = 0.8)
text(0.8, 0.4, paste("Radial AUC: ", round(auc.rad,4)), cex = 0.8)
text(0.8, 0.34, paste("Logistic AUC: ", round(auc.logit,4)), cex = 0.8)

Model Comparison
Regularized Classification vs Support Vector Machine
Classification:
Regularized classification (Lasso, Ridge, and Elastic Net) and
Support Vector Machine (SVM) classification exhibit distinct strengths.
Regularized classification models demonstrate high sensitivity (97.04%)
across all methods, meaning they effectively capture positive cases.
However, their specificity is relatively low (ranging from 35.71% to
39.29%), indicating they struggle with correctly identifying negatives.
In contrast, the SVM classifier achieves much higher specificity
(93.63%), meaning it is excellent at identifying negative cases, but its
sensitivity is significantly lower (51.26%), leading to a higher rate of
missed positive cases. Additionally, the SVM model has an overall
accuracy of 78.76%, balancing precision and recall with an optimized
cutoff of 0.1742. Ultimately, regularized classification models are
better suited when capturing positives is critical, whereas SVM is
preferable when correctly identifying negatives is a priority.
LS0tDQp0aXRsZTogIlVzaW5nIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmVzIGFuZCBSZWd1bGFyaXplZCBSZWdyZXNzaW9uIGZvciBCYW5rcnVwdGN5IFByZWRpY3Rpb24gaW4gUiINCmF1dGhvcjogIkJoYXZhbmEgS2FwcGFsYSINCmRhdGU6ICIyMDI1LTAzLTE4Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiAgDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCg0KDQpgYGB7PWh0bWx9DQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCi8qIENhc2NhZGluZyBTdHlsZSBTaGVldHMgKENTUykgaXMgYSBzdHlsZXNoZWV0IGxhbmd1YWdlIHVzZWQgdG8gZGVzY3JpYmUgdGhlIHByZXNlbnRhdGlvbiBvZiBhIGRvY3VtZW50IHdyaXR0ZW4gaW4gSFRNTCBvciBYTUwuIGl0IGlzIGEgc2ltcGxlIG1lY2hhbmlzbSBmb3IgYWRkaW5nIHN0eWxlIChlLmcuLCBmb250cywgY29sb3JzLCBzcGFjaW5nKSB0byBXZWIgZG9jdW1lbnRzLiAqLw0KDQpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGF1dGhvcnMgICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMjJweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMiB7IC8qIEhlYWRlciAyIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMiBzZWN0aW9uIHRpdGxlICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgNCBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQo8L3N0eWxlPg0KYGBgDQoNCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInNtb3RlZmFtaWx5IikpIHsNCmluc3RhbGwucGFja2FnZXMoInNtb3RlZmFtaWx5IikNCmxpYnJhcnkoc21vdGVmYW1pbHkpICAjIEZvciBTTU9URQ0KfQ0KDQppZiAoIXJlcXVpcmUoImh0bWx0b29scyIpKSB7DQojIFVwZGF0ZSB0aGUgaHRtbHRvb2xzIHBhY2thZ2UNCmluc3RhbGwucGFja2FnZXMoImh0bWx0b29scyIpDQpsaWJyYXJ5KGh0bWx0b29scykNCn0NCg0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiMgTG9hZCB0aGUgcGxvdGx5IHBhY2thZ2UNCmxpYnJhcnkocGxvdGx5KQ0KfQ0KDQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZiAoIXJlcXVpcmUoIlZJTSIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJWSU0iKSAgIyBGb3IgS05OIGltcHV0YXRpb24NCmxpYnJhcnkoVklNKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjYXJldCIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIpICAjIEZvciBvbmUtaG90IGVuY29kaW5nDQogIGxpYnJhcnkoY2FyZXQpDQp9DQppZiAoIXJlcXVpcmUoIm1pY2UiKSkgew0KaW5zdGFsbC5wYWNrYWdlcygibWljZSIpICAgIyBGb3IgbXVsdGlwbGUgaW1wdXRhdGlvbiAob3B0aW9uYWwpDQpsaWJyYXJ5KG1pY2UpDQp9DQoNCmlmICghcmVxdWlyZSgicFJPQyIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJwUk9DIikgICAjIEZvciBST0MgQ3VydmUNCmxpYnJhcnkocFJPQykNCn0NCmlmICghcmVxdWlyZSgiY2FUb29scyIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJjYVRvb2xzIikgICAjIEZvciBTcGxpdHRpbmcgRGF0YQ0KbGlicmFyeShjYVRvb2xzKQ0KfQ0KDQppZiAoIXJlcXVpcmUoImdnY29ycnBsb3QiKSkgew0KaW5zdGFsbC5wYWNrYWdlcygiZ2djb3JycGxvdCIpICAjIEluc3RhbGwgaWYgbmVlZGVkDQpsaWJyYXJ5KGdnY29ycnBsb3QpDQp9DQoNCg0KaWYgKCFyZXF1aXJlKCJza2ltciIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJza2ltciIpDQpsaWJyYXJ5KHNraW1yKQ0KfQ0KDQppZiAoIXJlcXVpcmUoIkRhdGFFeHBsb3JlciIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJEYXRhRXhwbG9yZXIiKQ0KbGlicmFyeShEYXRhRXhwbG9yZXIpDQp9DQoNCmlmICghcmVxdWlyZSgiZ2xtbmV0IikpIHsNCmluc3RhbGwucGFja2FnZXMoImdsbW5ldCIpDQpsaWJyYXJ5KGdsbW5ldCkNCn0NCg0KDQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KbGlicmFyeShwYW5kZXIpDQp9DQoNCmlmICghcmVxdWlyZSgiUk9DUiIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJST0NSIikNCmxpYnJhcnkoUk9DUikNCn0NCg0KaWYgKCFyZXF1aXJlKCJlMTA3MSIpKSB7DQppbnN0YWxsLnBhY2thZ2VzKCJlMTA3MSIpDQpsaWJyYXJ5KGUxMDcxKQ0KfQ0KIyMgDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQ0KICAgICAgICAgICAgICAgICAgICAgICkgIA0KYGBgDQoNCiMjIE9iamVjdGl2ZQ0KDQpUaGlzIHByb2plY3QgYWltcyB0byBkZXZlbG9wIGEgYmFua3J1cHRjeSBwcmVkaWN0aW9uIG1vZGVsIHVzaW5nIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmVzIChTVk0pIGFuZCBSZWd1bGFyaXplZCBSZWdyZXNzaW9uIHRlY2huaXF1ZXMgaW4gUi4gQnkgbGV2ZXJhZ2luZyBoaXN0b3JpY2FsIGZpbmFuY2lhbCBkYXRhLCB0aGUgbW9kZWwgd2lsbCBjbGFzc2lmeSBjb21wYW5pZXMgYmFzZWQgb24gdGhlaXIgbGlrZWxpaG9vZCBvZiBiYW5rcnVwdGN5LiBUaGUgb2JqZWN0aXZlIGlzIHRvIGNvbXBhcmUgdGhlIHBlcmZvcm1hbmNlIG9mIFNWTSBhbmQgcmVndWxhcml6ZWQgcmVncmVzc2lvbiBtZXRob2RzIGluIHRlcm1zIG9mIHByZWRpY3RpdmUgYWNjdXJhY3ksIGludGVycHJldGFiaWxpdHksIGFuZCByb2J1c3RuZXNzLiBBZGRpdGlvbmFsbHksIHRoZSBwcm9qZWN0IHNlZWtzIHRvIGlkZW50aWZ5IGtleSBmaW5hbmNpYWwgaW5kaWNhdG9ycyB0aGF0IGNvbnRyaWJ1dGUgdG8gYmFua3J1cHRjeSByaXNrLCBwcm92aWRpbmcgaW5zaWdodHMgZm9yIGZpbmFuY2lhbCBhbmFseXN0cyBhbmQgZGVjaXNpb24tbWFrZXJzLg0KDQojIyBJbnRyb2R1Y3Rpb24NCg0KRGVzY3JpcHRpb24gb2YgZGF0YToNCg0KMS4gKipCYW5rcnVwdCoqIChpbnQsIHRhcmdldCB2YXJpYWJsZSkg4oCTIEluZGljYXRlcyB3aGV0aGVyIGEgY29tcGFueSBoYXMgZ29uZSBiYW5rcnVwdCAoMCA9IE5vLCAxID0gWWVzKS4gIA0KMi4gKipDdXJyZW50X1JhdGlvKiogKGZsb2F0KSDigJMgTWVhc3VyZXMgYSBjb21wYW554oCZcyBhYmlsaXR5IHRvIHBheSBzaG9ydC10ZXJtIG9ibGlnYXRpb25zIChjdXJyZW50IGFzc2V0cyAvIGN1cnJlbnQgbGlhYmlsaXRpZXMpLiAgDQozLiAqKlF1aWNrX1JhdGlvKiogKGZsb2F0KSDigJMgQSBsaXF1aWRpdHkgbWV0cmljIHRoYXQgZXhjbHVkZXMgaW52ZW50b3J5IGZyb20gY3VycmVudCBhc3NldHMgKHF1aWNrIGFzc2V0cyAvIGN1cnJlbnQgbGlhYmlsaXRpZXMpLiAgDQo0LiAqKlRvdGFsX2RlYnRfYnlfVG90YWxfbmV0d29ydGgqKiAoZmxvYXQpIOKAkyBSZXByZXNlbnRzIHRoZSBjb21wYW554oCZcyB0b3RhbCBkZWJ0IGluIHByb3BvcnRpb24gdG8gaXRzIG5ldCB3b3J0aC4gIA0KNS4gKipEZWJ0X3JhdGlvX1BlcmNlbnQqKiAoZmxvYXQpIOKAkyBUaGUgcGVyY2VudGFnZSBvZiBhIGNvbXBhbnnigJlzIGFzc2V0cyBmaW5hbmNlZCBieSBkZWJ0ICh0b3RhbCBkZWJ0IC8gdG90YWwgYXNzZXRzICogMTAwKS4gIA0KNi4gKipPcGVyYXRpbmdfcHJvZml0X2J5X1BhaWRpbl9jYXBpdGFsKiogKGZsb2F0KSDigJMgTWVhc3VyZXMgcHJvZml0YWJpbGl0eSBpbiByZWxhdGlvbiB0byBwYWlkLWluIGNhcGl0YWwuICANCjcuICoqVG90YWxfQXNzZXRfVHVybm92ZXIqKiAoZmxvYXQpIOKAkyBJbmRpY2F0ZXMgaG93IGVmZmljaWVudGx5IGEgY29tcGFueSB1dGlsaXplcyBpdHMgYXNzZXRzIHRvIGdlbmVyYXRlIHNhbGVzLiAgDQo4LiAqKldvcmtpbmdfQ2FwaXRhbF90b19Ub3RhbF9Bc3NldHMqKiAoZmxvYXQpIOKAkyBQcm9wb3J0aW9uIG9mIHdvcmtpbmcgY2FwaXRhbCBpbiB0b3RhbCBhc3NldHMsIHJlZmxlY3RpbmcgbGlxdWlkaXR5LiAgDQo5LiAqKkNhc2hfRmxvd190b19Ub3RhbF9Bc3NldHMqKiAoZmxvYXQpIOKAkyBNZWFzdXJlcyBob3cgbXVjaCBjYXNoIGZsb3cgYSBjb21wYW55IGdlbmVyYXRlcyByZWxhdGl2ZSB0byBpdHMgdG90YWwgYXNzZXRzLiAgDQoxMC4gKipDYXNoX0Zsb3dfdG9fTGlhYmlsaXR5KiogKGZsb2F0KSDigJMgUmVwcmVzZW50cyB0aGUgcHJvcG9ydGlvbiBvZiBjYXNoIGZsb3cgYXZhaWxhYmxlIHRvIGNvdmVyIGxpYWJpbGl0aWVzLiAgDQoxMS4gKipDdXJyZW50X0xpYWJpbGl0eV90b19DdXJyZW50X0Fzc2V0cyoqIChmbG9hdCkg4oCTIFJhdGlvIG9mIGN1cnJlbnQgbGlhYmlsaXRpZXMgdG8gY3VycmVudCBhc3NldHMsIGluZGljYXRpbmcgbGlxdWlkaXR5IHJpc2suICANCjEyLiAqKkdyb3NzX1Byb2ZpdF90b19TYWxlcyoqIChmbG9hdCkg4oCTIFBlcmNlbnRhZ2Ugb2YgZ3Jvc3MgcHJvZml0IGdlbmVyYXRlZCBmcm9tIHRvdGFsIHNhbGVzIChncm9zcyBwcm9maXQgLyBzYWxlcykuICANCjEzLiAqKkxldmVyYWdlX1NEKiogKGNhdGVnb3JpY2FsKSDigJMgQ2F0ZWdvcml6ZWQgYXMgIkxvdywiICJNb2RlcmF0ZSwiIG9yIG90aGVyIGxldmVscywgcmVwcmVzZW50aW5nIHRoZSBjb21wYW55J3MgbGV2ZXJhZ2Ugcmlzay4gIA0KDQoNCmBgYHtyIGRhdGEsIGluY2x1ZGU9RkFMU0V9DQojIFJlYWQgdGhlIGRhdGFzZXQgZnJvbSBhIENTViBmaWxlDQpkZiA8LSByZWFkLmNzdigiaHR0cHM6Ly9iaGF2YW5hLWRvdGNvbS5naXRodWIuaW8vUHJvamVjdDIvZGF0YS5jc3YiKSAgIyBSZXBsYWNlIHdpdGggeW91ciBmaWxlIHBhdGgNCg0KIyBTYW1wbGUgMjAwMCByb3dzDQojc2V0LnNlZWQoMTIzKSAgIyBPcHRpb25hbDogU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQ0KI2RmIDwtIGRhdGFbc2FtcGxlKG5yb3coZGF0YSksIDEwMDApLCBdDQoNCiMgV3JpdGUgdGhlIHNhbXBsZWQgZGF0YSB0byBhIG5ldyBDU1YgZmlsZQ0KI3dyaXRlLmNzdihkZiwgIkM6L1VzZXJzL2FnYWphL0Rvd25sb2Fkcy9TVEEgNTUyIFByb2plY3QgMi9zYW1wbGVkX2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpICAjIFJlcGxhY2Ugd2l0aCB5b3VyIGRlc2lyZWQgb3V0cHV0IGZpbGUgcGF0aA0Kc3RyKGRmKQ0KYGBgDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQojc3VtbWFyeShkZiRUb3RhbF9kZWJ0X2J5X1RvdGFsX25ldHdvcnRoKQ0KI2hpc3QoZGYkVG90YWxfZGVidF9ieV9Ub3RhbF9uZXR3b3J0aCwgYnJlYWtzID0gMzAsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIERlYnQtdG8tTmV0IFdvcnRoIFJhdGlvIikNCm1lYW5fdmFsIDwtIG1lYW4oZGYkVG90YWxfZGVidF9ieV9Ub3RhbF9uZXR3b3J0aCwgbmEucm0gPSBUUlVFKQ0Kc2RfdmFsIDwtIHNkKGRmJFRvdGFsX2RlYnRfYnlfVG90YWxfbmV0d29ydGgsIG5hLnJtID0gVFJVRSkNCg0KZGYkTGV2ZXJhZ2VfU0QgPC0gY3V0KGRmJFRvdGFsX2RlYnRfYnlfVG90YWxfbmV0d29ydGgsIA0KICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgbWVhbl92YWwgLSBzZF92YWwsIG1lYW5fdmFsICsgc2RfdmFsLCBJbmYpLCANCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJMb3ciLCAiTW9kZXJhdGUiLCAiSGlnaCIpKQ0KDQpkZiRMZXZlcmFnZV9TRCA8LSBhcy5mYWN0b3IoZGYkTGV2ZXJhZ2VfU0QpDQoNCmBgYA0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQoNCiMgRnVuY3Rpb24gdG8gY291bnQgbWlzc2luZyB2YWx1ZXMgaW4gYWxsIHZhcmlhYmxlcw0KY291bnRfbWlzc2luZ192YWx1ZXMgPC0gZnVuY3Rpb24oZGF0YSkgew0KICBkYXRhICU+JQ0KICAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgfiBuYV9pZiguLCAiIikpKSAlPiUNCiAgICBzdW1tYXJpc2VfYWxsKH4gc3VtKGlzLm5hKC4pKSkgJT4lDQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAibWlzc2luZ19jb3VudCIpDQp9DQojIFVzZSB0aGUgZnVuY3Rpb24NCm1pc3NpbmdfdmFsdWVzIDwtIGNvdW50X21pc3NpbmdfdmFsdWVzKGRmKQ0KDQpwcmludChtaXNzaW5nX3ZhbHVlcykNCmBgYA0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0Kc3VtbWFyeShkZikNCnN0cihkZikNCmBgYA0KDQojIyBSZWxhdGlvbnNoaXAgYmV0d2VlbiBGZWF0dXJlcw0KDQoqKkNvcnJlbGF0aW9uIFBsb3QqKg0KDQpUaGUgY29ycmVsYXRpb24gbWF0cml4IGhlYXRtYXAgdmlzdWFsbHkgcmVwcmVzZW50cyB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGZpbmFuY2lhbCB2YXJpYWJsZXMgYW5kIGJhbmtydXB0Y3kgc3RhdHVzLiBOb3RhYmxlIGluc2lnaHRzIGluY2x1ZGUgYSBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuICoqQ3VycmVudCBSYXRpbyoqIGFuZCAqKkJhbmtydXB0Y3kgKC0wLjMyKSoqLCBpbmRpY2F0aW5nIHRoYXQgY29tcGFuaWVzIHdpdGggbG93ZXIgbGlxdWlkaXR5IGFyZSBtb3JlIGxpa2VseSB0byBnbyBiYW5rcnVwdC4gKipUb3RhbCBkZWJ0IHRvIFRvdGFsIG5ldCB3b3J0aCAoMC4zOCkqKiBhbmQgKipEZWJ0IFJhdGlvIFBlcmNlbnQgKDAuMjIpKiogc2hvdyBwb3NpdGl2ZSBjb3JyZWxhdGlvbnMgd2l0aCBiYW5rcnVwdGN5LCBzdWdnZXN0aW5nIGhpZ2hlciBsZXZlcmFnZSBpbmNyZWFzZXMgYmFua3J1cHRjeSByaXNrLiBBIHN0cm9uZyBwb3NpdGl2ZSBjb3JyZWxhdGlvbiAoKiowLjg3KiopIGV4aXN0cyBiZXR3ZWVuICoqQ2FzaCBGbG93IHRvIExpYWJpbGl0eSoqIGFuZCAqKkNhc2ggRmxvdyB0byBUb3RhbCBBc3NldHMqKiwgd2hpbGUgKipDdXJyZW50IFJhdGlvKiogYW5kICoqUXVpY2sgUmF0aW8qKiBhcmUgYWxzbyBoaWdobHkgY29ycmVsYXRlZCAoKiowLjc2KiopLCByZWZsZWN0aW5nIGludGVyZGVwZW5kZW5jaWVzIGFtb25nIGxpcXVpZGl0eSBtZXRyaWNzLiBUaGVzZSBpbnNpZ2h0cyBjYW4gYWlkIGluIGZpbmFuY2lhbCByaXNrIGFzc2Vzc21lbnQgYW5kIGJhbmtydXB0Y3kgcHJlZGljdGlvbiBtb2RlbGluZy4NCg0KYGBge3J9DQpkZl9udW0gPC0gZGYNCmRmX251bSRCYW5rcnVwdCA8LSBhcy5udW1lcmljKGFzLmZhY3RvcihkZl9udW0kQmFua3J1cHQpKQ0KbnVtZXJpY19mZWF0dXJlcyA8LSBkZl9udW0gJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKQ0KIyBDb21wdXRlIGNvcnJlbGF0aW9uIG1hdHJpeA0KY29yX21hdHJpeCA8LSBjb3IobnVtZXJpY19mZWF0dXJlcywgdXNlID0gImNvbXBsZXRlLm9icyIpDQoNCiMgUGxvdCBoZWF0bWFwDQpnZ2NvcnJwbG90KGNvcl9tYXRyaXgsIG1ldGhvZCA9ICJjaXJjbGUiLCB0eXBlID0gImxvd2VyIiwgbGFiID0gVFJVRSkNCg0KYGBgDQoNCg0KIyMgUmVsYXRpb25zaGlwIGJldHdlZW4gRmVhdHVyZXMNCg0KKipSZWxhdGlvbnNoaXAgYmV0d2VlbiBoaWdobHkgY29ycmVsYXRlZCBudW1lcmljYWwgZmVhdHVyZXMgdXNpbmcgU2NhdHRlciBQbG90KioNCg0KVGhlIHNjYXR0ZXIgcGxvdCBvZiBDYXNoIEZsb3cgdG8gVG90YWwgQXNzZXRzIChDRi9UQSkgdnMuIENhc2ggRmxvdyB0byBMaWFiaWxpdGllcyAoQ0YvTCkgcmV2ZWFscyBhIHN0cm9uZyBwb3NpdGl2ZSBjb3JyZWxhdGlvbiwgaW5kaWNhdGluZyB0aGF0IGZpcm1zIGdlbmVyYXRpbmcgaGlnaGVyIGNhc2ggZmxvdyByZWxhdGl2ZSB0byB0aGVpciBhc3NldHMgYWxzbyB0ZW5kIHRvIGhhdmUgaGlnaGVyIGNhc2ggZmxvdyByZWxhdGl2ZSB0byB0aGVpciBsaWFiaWxpdGllcy4gVGhlIG1ham9yaXR5IG9mIGRhdGEgcG9pbnRzIGNsdXN0ZXIgYWxvbmcgYSBsaW5lYXIgdHJlbmQsIHN1Z2dlc3RpbmcgYSBjb25zaXN0ZW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFzc2V0IHV0aWxpemF0aW9uIGFuZCBsaWFiaWxpdHkgY292ZXJhZ2UuIEEgZmV3IG91dGxpZXJzIGFib3ZlIHRoZSBtYWluIGNsdXN0ZXIgc3VnZ2VzdCBmaXJtcyB3aXRoIGV4Y2VwdGlvbmFsbHkgc3Ryb25nIGNhc2ggZmxvdyBtYW5hZ2VtZW50IG9yIGxvdyBsaWFiaWxpdGllcywgd2hpbGUgdGhvc2UgYmVsb3cgdGhlIHRyZW5kIG1heSBpbmRpY2F0ZSBjb21wYW5pZXMgc3RydWdnbGluZyB3aXRoIGRlYnQgcmVwYXltZW50LiBUaGlzIGFuYWx5c2lzIGhpZ2hsaWdodHMgdGhlIG92ZXJhbGwgZmluYW5jaWFsIGVmZmljaWVuY3kgYW5kIHBvdGVudGlhbCByaXNrIGZhY3RvcnMgd2l0aGluIHRoZSBkYXRhc2V0Lg0KDQoNCmBgYHtyfQ0KIyBTY2F0dGVyIHBsb3QgdXNpbmcgZ2dwbG90Mg0KZ2dwbG90KGRmLCBhZXMoeD1DYXNoX0Zsb3dfdG9fVG90YWxfQXNzZXRzLCB5PUNhc2hfRmxvd190b19MaWFiaWxpdHkpKSArDQogIGdlb21fcG9pbnQoY29sb3I9ImJsdWUiLCBhbHBoYT0wLjUpICsNCiAgZ2d0aXRsZSgiIENhc2ggRmxvdyB0byBUb3RhbCBBc3NldHMgdnMgQ2FzaCBGbG93IHRvIExpYWJpbGl0eSIpICsNCiAgeGxhYigiQ2FzaCBGbG93IHRvIFRvdGFsIEFzc2V0cyAiKSArDQogIHlsYWIoIkNhc2ggRmxvdyB0byBMaWFiaWxpdHkiKQ0KDQpgYGANCg0KDQoqKlJlbGF0aW9uc2hpcCBiZXR3ZWVuIFRhcmdldCBWYXJpYWJsZShCYW5rcnVwdCkgYW5kIGEgY2F0ZWdvcmljYWwgZmVhdHVyZSB1c2luZyBoZWF0bWFwKioNCg0KDQpUaGUgaGVhdG1hcCBpbGx1c3RyYXRlcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gKipsZXZlcmFnZSBsZXZlbCAoVG90YWwgRGVidCB0byBUb3RhbCBOZXQgV29ydGgpIGFuZCBiYW5rcnVwdGN5IHN0YXR1cyoqLiBUaGUgbWFqb3JpdHkgb2YgZmlybXMgY2xhc3NpZmllZCB1bmRlciB0aGUgKioiTW9kZXJhdGUiIGxldmVyYWdlIGNhdGVnb3J5KiogYXJlIG5vbi1iYW5rcnVwdCAoZGVlcCBibHVlKSwgd2hpbGUgYSBzbWFsbGVyIHBvcnRpb24gd2l0aGluIHRoaXMgY2F0ZWdvcnkgaGFzIGdvbmUgYmFua3J1cHQgKGxpZ2h0ZXIgcHVycGxlKS4gVGhlcmUgYXJlIG5vIGZpcm1zIGNhdGVnb3JpemVkIHVuZGVyICoqIkhpZ2giIGxldmVyYWdlKiosIHdoaWNoIG1pZ2h0IHN1Z2dlc3QgZGF0YSBpbWJhbGFuY2Ugb3IgYWJzZW5jZSBvZiBoaWdoLWxldmVyYWdlIGZpcm1zIGluIHRoZSBkYXRhc2V0LiBUaGlzIHZpc3VhbGl6YXRpb24gaGlnaGxpZ2h0cyB0aGF0IGNvbXBhbmllcyB3aXRoIG1vZGVyYXRlIGxldmVyYWdlIGFyZSBtb3JlIHByZXZhbGVudCwgYnV0IHNvbWUgc3RpbGwgZmFjZSBiYW5rcnVwdGN5IHJpc2tzLg0KDQoNCmBgYHtyfQ0KZGYkQmFua3J1cHQgPC0gYXMuZmFjdG9yKGRmJEJhbmtydXB0KQ0KDQpoZWF0bWFwX2RhdGEgPC0gZGYgJT4lDQogIGNvdW50KEJhbmtydXB0LCBMZXZlcmFnZV9TRCkNCg0KIyBIZWF0bWFwOiBSZWxhdGlvbnNoaXAgYmV0d2VlbiBEZWZhdWx0IGFuZCBFbXBsb3ltZW50IFN0YXR1cw0KZ2dwbG90KGhlYXRtYXBfZGF0YSwgYWVzKHggPSBCYW5rcnVwdCwgeSA9IExldmVyYWdlX1NEICwgZmlsbCA9IG4pKSArDQogIGdlb21fdGlsZSgpICsNCiAgbGFicyh0aXRsZSA9ICJIZWF0bWFwOiBCYW5rcnVwdCB2cyBMZXZlcmFnZSBMZXZlbCAoVG90YWwgRGVidCB0byBUb3RhbCBOZXQgV29ydGgpIiwNCiAgICAgICB4ID0gIkJhbmtydXB0IiwgeSA9ICJMZXZlcmFnZV9TRCIpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLCBoaWdoID0gImJsdWUiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCioqQm94IFBsb3QqKg0KDQpUaGUgYm94IHBsb3QgY29tcGFyZXMgdGhlICoqQ3VycmVudCBSYXRpbyoqIGJldHdlZW4gYmFua3J1cHQgYW5kIG5vbi1iYW5rcnVwdCBmaXJtcy4gTm9uLWJhbmtydXB0IGZpcm1zICh0ZWFsKSB0ZW5kIHRvIGhhdmUgYSBoaWdoZXIgbWVkaWFuIGN1cnJlbnQgcmF0aW8gY29tcGFyZWQgdG8gYmFua3J1cHQgZmlybXMgKHllbGxvdyksIGluZGljYXRpbmcgYmV0dGVyIGxpcXVpZGl0eS4gVGhlIGludGVycXVhcnRpbGUgcmFuZ2UgKElRUikgZm9yIG5vbi1iYW5rcnVwdCBmaXJtcyBpcyB3aWRlciwgc3VnZ2VzdGluZyBtb3JlIHZhcmlhdGlvbiBpbiBsaXF1aWRpdHkgbGV2ZWxzLiBCYW5rcnVwdCBmaXJtcyBoYXZlIGEgbG93ZXIgbWVkaWFuIGN1cnJlbnQgcmF0aW8sIHdpdGggYSBtb3JlIGNvbXByZXNzZWQgZGlzdHJpYnV0aW9uLCBzaG93aW5nIHRoYXQgbG93ZXIgbGlxdWlkaXR5IGlzIGFzc29jaWF0ZWQgd2l0aCBmaW5hbmNpYWwgZGlzdHJlc3MuIEFkZGl0aW9uYWxseSwgYm90aCBncm91cHMgaGF2ZSBvdXRsaWVycywgYnV0IHRoZSBub24tYmFua3J1cHQgZmlybXMgZXhoaWJpdCBhIGdyZWF0ZXIgcmFuZ2Ugb2YgaGlnaGVyIGN1cnJlbnQgcmF0aW9zLg0KDQoNCmBgYHtyfQ0KDQojIEJveCBQbG90OiBSZWxhdGlvbnNoaXAgYmV0d2VlbiBCYW5rcnVwdCAoQ2F0ZWdvcmljYWwpIGFuZCAgQ3VycmVudCBSYXRpbyAoTnVtZXJpY2FsKQ0KZ2dwbG90KGRmLCBhZXMoeCA9IEJhbmtydXB0LCB5ID0gQ3VycmVudF9SYXRpbywgZmlsbCA9IEJhbmtydXB0KSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiQm94IFBsb3Q6IEJhbmtydXB0IHZzIEN1cnJlbnQgUmF0aW8iLA0KICAgICAgIHggPSAiQmFua3J1cHQgU3RhdHVzIiwgeSA9ICJDdXJyZW50IFJhdGlvIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKQ0KDQpgYGANCg0KIyMgU2tld25lc3MNCg0KDQpUaGUgc2tld25lc3MgYW5hbHlzaXMgcmV2ZWFscyB0aGF0IHNldmVyYWwgZmluYW5jaWFsIHZhcmlhYmxlcyBleGhpYml0IHNpZ25pZmljYW50IHNrZXduZXNzLCBpbmRpY2F0aW5nIGFzeW1tZXRyaWMgZGlzdHJpYnV0aW9ucy4gKipIaWdobHkgc2tld2VkIHZhcmlhYmxlcyoqIGluY2x1ZGUgKipRdWljayBSYXRpbywgVG90YWwgRGVidCB0byBUb3RhbCBOZXQgV29ydGgsIERlYnQgUmF0aW8gUGVyY2VudCwgT3BlcmF0aW5nIFByb2ZpdCBieSBQYWlkLWluIENhcGl0YWwsIFRvdGFsIEFzc2V0IFR1cm5vdmVyLCBXb3JraW5nIENhcGl0YWwgdG8gVG90YWwgQXNzZXRzLCBDYXNoIEZsb3cgdG8gVG90YWwgQXNzZXRzLCBDYXNoIEZsb3cgdG8gTGlhYmlsaXR5LCBDdXJyZW50IExpYWJpbGl0eSB0byBDdXJyZW50IEFzc2V0cywgYW5kIEdyb3NzIFByb2ZpdCB0byBTYWxlcy4qKiBOb3RhYmx5LCAqKkNhc2ggRmxvdyB0byBMaWFiaWxpdHkgKC05LjU4KSoqIGFuZCAqKlRvdGFsIERlYnQgdG8gVG90YWwgTmV0IFdvcnRoICgxNi4yMykqKiBoYXZlIGV4dHJlbWUgc2tld25lc3MgdmFsdWVzLCBzdWdnZXN0aW5nIGEgc3Ryb25nIGRldmlhdGlvbiBmcm9tIG5vcm1hbGl0eS4gVGhlc2UgZmluZGluZ3MgaW5kaWNhdGUgcG90ZW50aWFsIGRhdGEgdHJhbnNmb3JtYXRpb25zIG1heSBiZSBuZWNlc3NhcnkgZm9yIHN0YXRpc3RpY2FsIG1vZGVsaW5nLg0KDQpgYGB7cn0NCg0KDQojIFNlbGVjdCBvbmx5IG51bWVyaWMgY29sdW1ucw0KbnVtZXJpY192YXJzIDwtIGRmWywgc2FwcGx5KGRmLCBpcy5udW1lcmljKV0NCiMgQ29tcHV0ZSBza2V3bmVzcyBmb3IgZWFjaCBudW1lcmljIHZhcmlhYmxlDQpza2V3bmVzc192YWx1ZXMgPC0gc2FwcGx5KG51bWVyaWNfdmFycywgc2tld25lc3MsIG5hLnJtID0gVFJVRSkNCg0KIyBJZGVudGlmeSBoaWdobHkgc2tld2VkIHZhcmlhYmxlcw0Kc2tld2VkX3ZhcnMgPC0gbmFtZXMoc2tld25lc3NfdmFsdWVzW2Ficyhza2V3bmVzc192YWx1ZXMpID4gMV0pDQoNCiMgUHJpbnQgcmVzdWx0cw0KI3ByaW50KCJTa2V3bmVzcyB2YWx1ZXM6IikNCiNwcmludChza2V3bmVzc192YWx1ZXMpDQpwcmludCgiSGlnaGx5IHNrZXdlZCB2YXJpYWJsZXM6IikNCnByaW50KHNrZXdlZF92YXJzKQ0KIyBDcmVhdGUgYSBoaXN0b2dyYW0gZm9yIFNrZXdlZCBOdW1lcmljIFZhcmlhYmxlIC0gTm8gb2YgQ3JlZGl0IEFjY291bnRzDQojaGlzdChudW1lcmljX3ZhcnMkTm9fb2ZfY3JlZGl0X2FjYywgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTm8gb2YgQ3JlZGl0IEFjY291bnRzIiwgeGxhYiA9ICJObyBvZiBDcmVkaXQgQWNjb3VudHMiLCAgICAgIGNvbCA9ICJsaWdodGJsdWUiLCAgICAgIGJyZWFrcyA9IDMwKQ0KDQoNCmBgYA0KDQojIyBGZWF0dXJlIFRyYW5zZm9ybWF0aW9uLCBTdGFuZGFyZGl6YXRpb24gJiBOb3JtYWxpemF0aW9uDQoNCkZlYXR1cmUgdHJhbnNmb3JtYXRpb24gYW5kIHN0YW5kYXJkaXphdGlvbiBhcmUgZXNzZW50aWFsIGZvciByZWd1bGFyaXplZCByZWdyZXNzaW9uIHRlY2huaXF1ZXMgbGlrZSBSaWRnZSwgTGFzc28sIGFuZCBFbGFzdGljIE5ldCB0byBlbnN1cmUgb3B0aW1hbCBtb2RlbCBwZXJmb3JtYW5jZS4gTWFueSBmaW5hbmNpYWwgcmF0aW9zIGV4aGliaXQgaGlnaCBza2V3bmVzcywgd2hpY2ggY2FuIGRpc3RvcnQgcmVsYXRpb25zaGlwcyBhbmQgcmVkdWNlIHByZWRpY3RpdmUgYWNjdXJhY3kuIEFwcGx5aW5nIHRyYW5zZm9ybWF0aW9ucyAoc3VjaCBhcyBsb2cgb3IgQm94LUNveCkgaGVscHMgbm9ybWFsaXplIHRoZXNlIGRpc3RyaWJ1dGlvbnMsIGltcHJvdmluZyBtb2RlbCBzdGFiaWxpdHkuIEFkZGl0aW9uYWxseSwgc3RhbmRhcmRpemF0aW9uIGVuc3VyZXMgdGhhdCBhbGwgZmVhdHVyZXMgY29udHJpYnV0ZSBlcXVhbGx5IHRvIHRoZSByZWd1bGFyaXphdGlvbiBwZW5hbHR5LCBwcmV2ZW50aW5nIHZhcmlhYmxlcyB3aXRoIGxhcmdlciBzY2FsZXMgZnJvbSBkb21pbmF0aW5nIHRoZSBtb2RlbC4gVGhpcyBwcmVwcm9jZXNzaW5nIHN0ZXAgZW5oYW5jZXMgaW50ZXJwcmV0YWJpbGl0eSwgbWl0aWdhdGVzIG11bHRpY29sbGluZWFyaXR5LCBhbmQgaW1wcm92ZXMgY29udmVyZ2VuY2UgaW4gb3B0aW1pemF0aW9uIGFsZ29yaXRobXMsIGxlYWRpbmcgdG8gbW9yZSByZWxpYWJsZSBhbmQgZ2VuZXJhbGl6YWJsZSBwcmVkaWN0aW9ucy4NCg0KDQpgYGB7cn0NCg0KZGZfbm9ybV9zdGFuIDwtIGRmDQpkZl9ub3JtX3N0YW4kQmFua3J1cHQgPC0gYXMubnVtZXJpYyhhcy5mYWN0b3IoZGYkQmFua3J1cHQpKQ0KZGZfbm9ybV9zdGFuJExldmVyYWdlX1NEIDwtIGFzLm51bWVyaWMoYXMuZmFjdG9yKGRmJExldmVyYWdlX1NEKSkNCg0KIyBOb3JtYWxpemF0aW9uDQpub3JtYWxpemUgPC0gZnVuY3Rpb24oeCkgew0KICByZXR1cm4oKHggLSBtaW4oeCkpIC8gKG1heCh4KSAtIG1pbih4KSkpDQp9DQpkZl9ub3JtX3N0YW4kQ3VycmVudF9SYXRpb19ub3JtIDwtIG5vcm1hbGl6ZShkZiRDdXJyZW50X1JhdGlvKQ0KZGZfbm9ybV9zdGFuJFF1aWNrX1JhdGlvX25vcm0gPC0gbm9ybWFsaXplKGRmJFF1aWNrX1JhdGlvKQ0KZGZfbm9ybV9zdGFuJFRvdGFsX2RlYnRfYnlfVG90YWxfbmV0d29ydGhfbm9ybSA8LSBub3JtYWxpemUoZGYkVG90YWxfZGVidF9ieV9Ub3RhbF9uZXR3b3J0aCkNCmRmX25vcm1fc3RhbiRPcGVyYXRpbmdfcHJvZml0X2J5X1BhaWRpbl9jYXBpdGFsX25vcm0gPC0gbm9ybWFsaXplKGRmJE9wZXJhdGluZ19wcm9maXRfYnlfUGFpZGluX2NhcGl0YWwpDQpkZl9ub3JtX3N0YW4kVG90YWxfQXNzZXRfVHVybm92ZXJfbm9ybSA8LSBub3JtYWxpemUoZGYkVG90YWxfQXNzZXRfVHVybm92ZXIpDQpkZl9ub3JtX3N0YW4kQ2FzaF9GbG93X3RvX1RvdGFsX0Fzc2V0c19ub3JtIDwtIG5vcm1hbGl6ZShkZiRDYXNoX0Zsb3dfdG9fVG90YWxfQXNzZXRzKQ0KZGZfbm9ybV9zdGFuJENhc2hfRmxvd190b19MaWFiaWxpdHlfbm9ybSA8LSBub3JtYWxpemUoZGYkQ2FzaF9GbG93X3RvX0xpYWJpbGl0eSkNCmRmX25vcm1fc3RhbiRDdXJyZW50X0xpYWJpbGl0eV90b19DdXJyZW50X0Fzc2V0c19ub3JtIDwtIG5vcm1hbGl6ZShkZiRDdXJyZW50X0xpYWJpbGl0eV90b19DdXJyZW50X0Fzc2V0cykNCmRmX25vcm1fc3RhbiRHcm9zc19Qcm9maXRfdG9fU2FsZXNfbm9ybSA8LSBub3JtYWxpemUoZGYkR3Jvc3NfUHJvZml0X3RvX1NhbGVzKQ0KZGZfbm9ybV9zdGFuJERlYnRfcmF0aW9fUGVyY2VudF9ub3JtIDwtIG5vcm1hbGl6ZShkZiREZWJ0X3JhdGlvX1BlcmNlbnQpDQpkZl9ub3JtX3N0YW4kV29ya2luZ19DYXBpdGFsX3RvX1RvdGFsX0Fzc2V0cyA8LSBub3JtYWxpemUoZGYkV29ya2luZ19DYXBpdGFsX3RvX1RvdGFsX0Fzc2V0cykNCg0KDQojIExvZyB0cmFuc2Zvcm1hdGlvbg0KDQoNCmRmX25vcm1fc3RhbiRRdWlja19SYXRpb190cmFucyA8LSBsb2coZGYkUXVpY2tfUmF0aW8gKyAxKQ0KZGZfbm9ybV9zdGFuJFRvdGFsX2RlYnRfYnlfVG90YWxfbmV0d29ydGhfdHJhbnMgPC0gbG9nKGRmJFRvdGFsX2RlYnRfYnlfVG90YWxfbmV0d29ydGggKyAxKQ0KZGZfbm9ybV9zdGFuJE9wZXJhdGluZ19wcm9maXRfYnlfUGFpZGluX2NhcGl0YWxfdHJhbnMgPC0gbG9nKGRmJE9wZXJhdGluZ19wcm9maXRfYnlfUGFpZGluX2NhcGl0YWwrMSkNCmRmX25vcm1fc3RhbiRUb3RhbF9Bc3NldF9UdXJub3Zlcl90cmFucyA8LSBsb2coZGYkVG90YWxfQXNzZXRfVHVybm92ZXIrMSkNCmRmX25vcm1fc3RhbiRDYXNoX0Zsb3dfdG9fVG90YWxfQXNzZXRzX3RyYW5zIDwtIGxvZyhkZiRDYXNoX0Zsb3dfdG9fVG90YWxfQXNzZXRzKzEpDQpkZl9ub3JtX3N0YW4kQ2FzaF9GbG93X3RvX0xpYWJpbGl0eV90cmFucyA8LSBsb2coZGYkQ2FzaF9GbG93X3RvX0xpYWJpbGl0eSsxKQ0KZGZfbm9ybV9zdGFuJEN1cnJlbnRfTGlhYmlsaXR5X3RvX0N1cnJlbnRfQXNzZXRzX3RyYW5zIDwtIGxvZyhkZiRDdXJyZW50X0xpYWJpbGl0eV90b19DdXJyZW50X0Fzc2V0cysxKQ0KZGZfbm9ybV9zdGFuJEdyb3NzX1Byb2ZpdF90b19TYWxlc190cmFucyA8LSBsb2coZGYkR3Jvc3NfUHJvZml0X3RvX1NhbGVzKzEpDQpkZl9ub3JtX3N0YW4kRGVidF9yYXRpb19QZXJjZW50X3RyYW5zIDwtIGxvZyhkZiREZWJ0X3JhdGlvX1BlcmNlbnQrMSkNCmRmX25vcm1fc3RhbiRXb3JraW5nX0NhcGl0YWxfdG9fVG90YWxfQXNzZXRzX3RyYW5zIDwtIGxvZyhkZiRXb3JraW5nX0NhcGl0YWxfdG9fVG90YWxfQXNzZXRzKzEpDQoNCg0KDQojIFN0YW5kYXJkaXphdGlvbg0Kc3RhbmRhcmRpemUgPC0gZnVuY3Rpb24oeCkgew0KICByZXR1cm4oKHggLSBtZWFuKHgpKSAvIHNkKHgpKQ0KfQ0KDQpkZl9ub3JtX3N0YW4kQ3VycmVudF9SYXRpb19zdGFuZCA8LSBzdGFuZGFyZGl6ZShkZl9ub3JtX3N0YW4kQ3VycmVudF9SYXRpbykNCmRmX25vcm1fc3RhbiRRdWlja19SYXRpb19zdGFuZCA8LSBzdGFuZGFyZGl6ZShkZl9ub3JtX3N0YW4kUXVpY2tfUmF0aW9fdHJhbnMpDQpkZl9ub3JtX3N0YW4kVG90YWxfZGVidF9ieV9Ub3RhbF9uZXR3b3J0aF9zdGFuZCA8LSBzdGFuZGFyZGl6ZShkZl9ub3JtX3N0YW4kVG90YWxfZGVidF9ieV9Ub3RhbF9uZXR3b3J0aF90cmFucykNCmRmX25vcm1fc3RhbiRPcGVyYXRpbmdfcHJvZml0X2J5X1BhaWRpbl9jYXBpdGFsX3N0YW5kIDwtIHN0YW5kYXJkaXplKGRmX25vcm1fc3RhbiRPcGVyYXRpbmdfcHJvZml0X2J5X1BhaWRpbl9jYXBpdGFsX3RyYW5zKQ0KZGZfbm9ybV9zdGFuJFRvdGFsX0Fzc2V0X1R1cm5vdmVyX3N0YW5kIDwtIHN0YW5kYXJkaXplKGRmX25vcm1fc3RhbiRUb3RhbF9Bc3NldF9UdXJub3Zlcl90cmFucykNCmRmX25vcm1fc3RhbiRDYXNoX0Zsb3dfdG9fVG90YWxfQXNzZXRzX3N0YW5kIDwtIHN0YW5kYXJkaXplKGRmX25vcm1fc3RhbiRDYXNoX0Zsb3dfdG9fVG90YWxfQXNzZXRzX3RyYW5zKQ0KZGZfbm9ybV9zdGFuJENhc2hfRmxvd190b19MaWFiaWxpdHlfc3RhbmQgPC0gc3RhbmRhcmRpemUoZGZfbm9ybV9zdGFuJENhc2hfRmxvd190b19MaWFiaWxpdHlfdHJhbnMpDQpkZl9ub3JtX3N0YW4kQ3VycmVudF9MaWFiaWxpdHlfdG9fQ3VycmVudF9Bc3NldHNfc3RhbmQgPC0gc3RhbmRhcmRpemUoZGZfbm9ybV9zdGFuJEN1cnJlbnRfTGlhYmlsaXR5X3RvX0N1cnJlbnRfQXNzZXRzX3RyYW5zKQ0KZGZfbm9ybV9zdGFuJEdyb3NzX1Byb2ZpdF90b19TYWxlc19zdGFuZCA8LSBzdGFuZGFyZGl6ZShkZl9ub3JtX3N0YW4kR3Jvc3NfUHJvZml0X3RvX1NhbGVzX3RyYW5zKQ0KZGZfbm9ybV9zdGFuJERlYnRfcmF0aW9fUGVyY2VudF9zdGFuZCA8LSBzdGFuZGFyZGl6ZShkZl9ub3JtX3N0YW4kRGVidF9yYXRpb19QZXJjZW50X3RyYW5zKQ0KZGZfbm9ybV9zdGFuJFdvcmtpbmdfQ2FwaXRhbF90b19Ub3RhbF9Bc3NldHNfc3RhbmQgPC0gc3RhbmRhcmRpemUoZGZfbm9ybV9zdGFuJFdvcmtpbmdfQ2FwaXRhbF90b19Ub3RhbF9Bc3NldHNfdHJhbnMpDQoNCg0KI2Z1bGxfbW9kZWwgPC0gZ2xtKERlZmF1bHQgfiAuLCBkYXRhID0gbmV3X2RmLCBmYW1pbHkgPSBiaW5vbWlhbCkgIA0KI3N1bW1hcnkoZnVsbF9tb2RlbCkNCg0KI2ZpbmFsX21vZGVsIDwtIGdsbShEZWZhdWx0IH4gQ2hlY2tpbmdfYW1vdW50K1Rlcm0rQ3JlZGl0X3Njb3JlK0FnZSwgZGF0YSA9IG5ld19kZiwgZmFtaWx5ID0gYmlub21pYWwgKQ0KI3N1bW1hcnkoZmluYWxfbW9kZWwpDQoNCiMgS2VlcCBvbmx5IHN0YW5kYXJkaXplZCBjb2x1bW5zIGFuZCB0YXJnZXQgdmFyaWFibGUNCmRmX3N0YW4gPC0gZGZfbm9ybV9zdGFuICU+JSBzZWxlY3QoQmFua3J1cHQsIExldmVyYWdlX1NELCBlbmRzX3dpdGgoIl9zdGFuZCIpKQ0KDQojIFZpZXcgc3RydWN0dXJlIG9mIHRoZSBzdGFuZGFyZGl6ZWQgZGF0YXNldA0KI3N0cihkZl9zdGFuKQ0KDQpgYGANCg0KIyMgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcw0KDQpUaGUgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyAoUENBKSByZXN1bHRzIGluZGljYXRlIHRoYXQgdGhlIGZpcnN0IGZldyBwcmluY2lwYWwgY29tcG9uZW50cyBjYXB0dXJlIG1vc3Qgb2YgdGhlIHZhcmlhbmNlIGluIHRoZSBkYXRhc2V0LCB3aXRoIFBDMSBhbG9uZSBleHBsYWluaW5nIDI3LjclIGFuZCB0aGUgZmlyc3QgZml2ZSBjb21wb25lbnRzIGFjY291bnRpbmcgZm9yIGFwcHJveGltYXRlbHkgNzAuNyUgb2YgdGhlIHRvdGFsIHZhcmlhbmNlLiBUaGUgc2NyZWUgcGxvdCBmdXJ0aGVyIGNvbmZpcm1zIHRoYXQgYmV5b25kIGEgY2VydGFpbiBudW1iZXIgb2YgY29tcG9uZW50cywgdGhlIHZhcmlhbmNlIGV4cGxhaW5lZCBkcm9wcyBzaWduaWZpY2FudGx5LCBzdWdnZXN0aW5nIHRoYXQgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIGlzIGZlYXNpYmxlLiBUaGUgc2NhdHRlciBwbG90IG9mIHRoZSBmaXJzdCB0d28gcHJpbmNpcGFsIGNvbXBvbmVudHMgc2hvd3Mgc29tZSBjbHVzdGVyaW5nIGJ1dCBhbHNvIGhpZ2hsaWdodHMgb3V0bGllcnMgdGhhdCBtYXkgaW5mbHVlbmNlIHRoZSBhbmFseXNpcy4gT3ZlcmFsbCwgYXBwbHlpbmcgUENBIGluIHRoaXMgcHJvamVjdCBpcyBiZW5lZmljaWFsIGFzIGl0IGhlbHBzIHJlZHVjZSBkaW1lbnNpb25hbGl0eSB3aGlsZSByZXRhaW5pbmcgbW9zdCBvZiB0aGUgaW1wb3J0YW50IGluZm9ybWF0aW9uLCBpbXByb3ZpbmcgbW9kZWwgZWZmaWNpZW5jeSBhbmQgaW50ZXJwcmV0YWJpbGl0eSwgZXNwZWNpYWxseSB3aGVuIGRlYWxpbmcgd2l0aCBoaWdobHkgY29ycmVsYXRlZCBhbmQgc2tld2VkIHZhcmlhYmxlcy4NCg0KYGBge3J9DQoNCiMgU3RlcCAxOiBDb252ZXJ0IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB0byBudW1lcmljIHVzaW5nIG9uZS1ob3QgZW5jb2RpbmcNCmRmX251bWVyaWMgPC0gZGYgJT4lDQogbXV0YXRlKGFjcm9zcyhjKEJhbmtydXB0LCBMZXZlcmFnZV9TRCksIGFzLmZhY3RvcikpICU+JSAgIyBDb252ZXJ0IHRvIGZhY3RvcnMNCiAgIGR1bW15VmFycyh+IC4sIGRhdGEgPSAuKSAlPiUgICAgICANCiAgcHJlZGljdChuZXdkYXRhID0gZGYpICU+JSANCiAgIGFzLmRhdGEuZnJhbWUoKQ0KIA0KICMgU3RlcCAyOiBTZWxlY3Qgb25seSBudW1lcmljIGZlYXR1cmVzDQogbnVtZXJpY19kYXRhIDwtIGRmX251bWVyaWMgJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKQ0KIA0KICMgU3RlcCAzOiBIYW5kbGUgbWlzc2luZyBhbmQgaW5maW5pdGUgdmFsdWVzDQogbnVtZXJpY19kYXRhW2lzLm5hKG51bWVyaWNfZGF0YSldIDwtIDAgICAjIFJlcGxhY2UgTkFzIHdpdGggMCAob3IgdXNlIG1lZGlhbiBpbXB1dGF0aW9uKQ0KIA0KIGNvbnN0YW50X2NvbHMgPC0gYXBwbHkobnVtZXJpY19kYXRhLCAyLCBmdW5jdGlvbihjb2wpIHZhcihjb2wsIG5hLnJtID0gVFJVRSkgPT0gMCkNCm51bWVyaWNfZGF0YSA8LSBudW1lcmljX2RhdGFbLCAhY29uc3RhbnRfY29sc10NCg0KIA0KICMgU3RlcCA0OiBTdGFuZGFyZGl6ZSB0aGUgZGF0YSAob25seSBhZnRlciBoYW5kbGluZyBtaXNzaW5nIHZhbHVlcykNCiBzY2FsZWRfZGF0YSA8LSBzY2FsZShudW1lcmljX2RhdGEpDQogDQogIyBTdGVwIDU6IFBlcmZvcm0gUENBDQogcGNhX3Jlc3VsdCA8LSBwcmNvbXAoc2NhbGVkX2RhdGEsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkNCiANCiBzdW1tYXJ5KHBjYV9yZXN1bHQpDQogDQogIyBTdGVwIDY6IFNjcmVlIFBsb3QgKHRvIGRlY2lkZSBudW1iZXIgb2YgY29tcG9uZW50cyB0byBrZWVwKQ0KIHNjcmVlcGxvdChwY2FfcmVzdWx0LCB0eXBlID0gImxpbmVzIiwgbWFpbiA9ICJTY3JlZSBQbG90IikNCiANCiAjIFN0ZXAgNzogQmlwbG90IChQQ0EgdmlzdWFsaXphdGlvbikNCiMgYmlwbG90KHBjYV9yZXN1bHQsIHNjYWxlID0gMCkNCiANCiAjIFN0ZXAgODogU2NhdHRlciBwbG90IG9mIGZpcnN0IHR3byBwcmluY2lwYWwgY29tcG9uZW50cw0KIHBjYV9kZiA8LSBhcy5kYXRhLmZyYW1lKHBjYV9yZXN1bHQkeCkNCiBnZ3Bsb3QocGNhX2RmLCBhZXMoeCA9IFBDMSwgeSA9IFBDMikpICsNCiAgIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC43LCBjb2xvciA9ICJibHVlIikgKw0KIGxhYnModGl0bGUgPSAiUENBIC0gRmlyc3QgVHdvIFByaW5jaXBhbCBDb21wb25lbnRzIikgKw0KICAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQoNCiMjIFJlZ3VsYXJpemF0aW9uDQoNCisgUmVndWxhcml6ZWQgTG9naXN0aWMgUmVncmVzc2lvbjoNCg0KDQpUaGUgcmVzdWx0cyBmcm9tIHRoZSBMQVNTTyByZWd1bGFyaXplZCByZWdyZXNzaW9uIGFuYWx5c2lzIHByb3ZpZGUga2V5IGluc2lnaHRzIGludG8gZmVhdHVyZSBzZWxlY3Rpb24gYW5kIG1vZGVsIHBlcmZvcm1hbmNlLg0KDQpDb2VmZmljaWVudCBQYXRoIFBsb3QgKExlZnQgUGFuZWwpOiBUaGlzIHBsb3Qgc2hvd3MgaG93IHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBzaHJpbmsgYXMgdGhlIHJlZ3VsYXJpemF0aW9uIHBhcmFtZXRlciAozrspIGluY3JlYXNlcy4gSW5pdGlhbGx5LCBhdCBsb3cgzrsgdmFsdWVzIChyaWdodCBzaWRlIG9mIHRoZSBwbG90KSwgbW9zdCBwcmVkaWN0b3JzIGhhdmUgbm9uemVybyBjb2VmZmljaWVudHMsIG1lYW5pbmcgdGhleSBhcmUgYWN0aXZlbHkgY29udHJpYnV0aW5nIHRvIHRoZSBtb2RlbC4gQXMgzrsgaW5jcmVhc2VzIChtb3ZpbmcgbGVmdCksIG1hbnkgY29lZmZpY2llbnRzIHNocmluayB0b3dhcmQgemVybywgZGVtb25zdHJhdGluZyBMQVNTT+KAmXMgYWJpbGl0eSB0byBlbmZvcmNlIHNwYXJzaXR5IGJ5IHNlbGVjdGluZyBvbmx5IHRoZSBtb3N0IGltcG9ydGFudCBmZWF0dXJlcy4gVGhlIHJlZCBkYXNoZWQgbGluZSByZXByZXNlbnRzIHRoZSDOuyB2YWx1ZSB0aGF0IG1pbmltaXplcyBjcm9zcy12YWxpZGF0aW9uIGVycm9yLCBzdHJpa2luZyBhIGJhbGFuY2UgYmV0d2VlbiBtb2RlbCBjb21wbGV4aXR5IGFuZCBwcmVkaWN0aXZlIHBvd2VyLiBUaGUgYmx1ZSBkYXNoZWQgbGluZSByZXByZXNlbnRzIHRoZSBtb3N0IHJlZ3VsYXJpemVkIG1vZGVsIHdpdGhpbiBvbmUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1pbmltdW0gY3Jvc3MtdmFsaWRhdGlvbiBlcnJvciwgb2Z0ZW4gY2hvc2VuIGZvciBiZXR0ZXIgZ2VuZXJhbGl6YXRpb24uDQoNCk1vZGVsIEZpdCBQbG90IChSaWdodCBQYW5lbCk6IFRoaXMgcGxvdCBpbGx1c3RyYXRlcyB0aGUgYmlub21pYWwgZGV2aWFuY2UgKGEgbWVhc3VyZSBvZiBtb2RlbCBlcnJvcikgZm9yIGRpZmZlcmVudCDOuyB2YWx1ZXMuIFRoZSBjdXJ2ZSBpbml0aWFsbHkgZGVjcmVhc2VzLCBpbmRpY2F0aW5nIHRoYXQgbW9kZXJhdGUgcmVndWxhcml6YXRpb24gaW1wcm92ZXMgbW9kZWwgcGVyZm9ybWFuY2UgYnkgcmVkdWNpbmcgb3ZlcmZpdHRpbmcuIFRoZSByZWQgcG9pbnRzIHJlcHJlc2VudCBtZWFuIGRldmlhbmNlIHZhbHVlcywgd2l0aCBlcnJvciBiYXJzIHNob3dpbmcgdmFyaWFiaWxpdHkuIFRoZSBkZXZpYW5jZSByZWFjaGVzIGl0cyBsb3dlc3QgcG9pbnQgYXJvdW5kIM674omI4oiSNSAobG9nIHNjYWxlKSwgYWZ0ZXIgd2hpY2ggaXQgaW5jcmVhc2VzIGFzIGV4Y2Vzc2l2ZSByZWd1bGFyaXphdGlvbiByZW1vdmVzIHRvbyBtYW55IGltcG9ydGFudCBmZWF0dXJlcywgbGVhZGluZyB0byB1bmRlcmZpdHRpbmcuDQoNCg0KYGBge3J9DQoNCg0KDQpkZiA8LSBkZl9zdGFuDQoNCiMgU3BsaXQgdGhlIGRhdGEgaW50byBwcmVkaWN0b3JzIChYKSBhbmQgcmVzcG9uc2UgKHkpDQpYIDwtIG1vZGVsLm1hdHJpeChCYW5rcnVwdCB+IC4sIGRmX3N0YW4pWywtMV0gICMgUmVtb3ZlIHRoZSBpbnRlcmNlcHQgY29sdW1uDQp5IDwtIGRmJEJhbmtydXB0DQoNCiMgU3BsaXQgdGhlIGRhdGEgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXRzDQpzZXQuc2VlZCgxMjMpDQp0cmFpbkluZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oeSwgcCA9IDAuOCwgbGlzdCA9IEZBTFNFKQ0KWF90cmFpbiA8LSBYW3RyYWluSW5kZXgsIF0NClhfdGVzdCA8LSBYWy10cmFpbkluZGV4LCBdDQp5X3RyYWluIDwtIHlbdHJhaW5JbmRleF0NCnlfdGVzdCA8LSB5Wy10cmFpbkluZGV4XQ0KDQojdGFibGUoeV90ZXN0KQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgRml0IExBU1NPIG1vZGVsDQojIyMjIyMjIyMjIyMjIyMjIyMjIw0KbGFzc29fbW9kZWwgPC0gZ2xtbmV0KFhfdHJhaW4sIHlfdHJhaW4sIGZhbWlseSA9ICJiaW5vbWlhbCIsIGFscGhhID0gMSkNCg0KIyBDcm9zcy12YWxpZGF0aW9uIHRvIGZpbmQgdGhlIG9wdGltYWwgbGFtYmRhDQpjdl9sYXNzbyA8LSBjdi5nbG1uZXQoWF90cmFpbiwgeV90cmFpbiwgZmFtaWx5ID0gImJpbm9taWFsIiwgYWxwaGEgPSAxKQ0KDQojIE9wdGltYWwgbGFtYmRhDQpsYW1iZGFfbGFzc28gPC0gY3ZfbGFzc28kbGFtYmRhLm1pbg0KDQojIFJlZml0IHRoZSBtb2RlbCB3aXRoIHRoZSBvcHRpbWFsIGxhbWJkYQ0KbGFzc29fbW9kZWxfb3B0IDwtIGdsbW5ldChYX3RyYWluLCB5X3RyYWluLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSA9IGxhbWJkYV9sYXNzbykNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIyBWaXN1YWxpemUgdGhlIGltcGFjdCBvZiBsYW1iZGEgb24gc2hyaW5raW5nIGNvZWZmaWNpZW50cw0KIyBQbG90IGNvZWZmaWNpZW50IHBhdGhzDQpwYXIobWFyPWMoNSw0LDYsMiksIG1mcm93PWMoMSwyKSkgIyANCnBsb3QobGFzc29fbW9kZWwsIHh2YXIgPSAibGFtYmRhIiwgbGFiZWwgPSBUUlVFLA0KICAgICBjb2wgPSByYWluYm93KDgpLA0KICAgICBsd2QgPSAxLA0KICAgICBtYWluID0gIkNvZWZmaWNpZW50IFBhdGggUGxvdDogTEFTU08iLA0KICAgICBjZXgubWFpbiA9IDAuOCkNCnRleHQoLTYsIDAuNCwgIm1pbmltdW0gQ1YgZXJyb3IiLCBjb2w9InJlZCIsIGNleCA9IDAuNiApDQphYmxpbmUodiA9IGxvZyhjdl9sYXNzbyRsYW1iZGEubWluKSwgY29sID0gInJlZCIsIGx0eSA9IDQsIGx3ZCA9IDEpDQphYmxpbmUodiA9IGxvZyhjdl9sYXNzbyRsYW1iZGEuMXNlKSwgY29sID0gImJsdWUiLCBsdHkgPSA0LCBsd2QgPSAxKQ0KDQpwbG90KGN2X2xhc3NvLCBtYWluPSJNZWFzdXJlIG9mIE1vZGVsIEZpdDogTEFTU08iLCBjZXgubWFpbiA9IDAuOCkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIEZpdCBSaWRnZSBtb2RlbA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMNCnJpZGdlX21vZGVsIDwtIGdsbW5ldChYX3RyYWluLCB5X3RyYWluLCBmYW1pbHkgPSAiYmlub21pYWwiLCBhbHBoYSA9IDApDQoNCiMgQ3Jvc3MtdmFsaWRhdGlvbiB0byBmaW5kIHRoZSBvcHRpbWFsIGxhbWJkYQ0KY3ZfcmlkZ2UgPC0gY3YuZ2xtbmV0KFhfdHJhaW4sIHlfdHJhaW4sIGZhbWlseSA9ICJiaW5vbWlhbCIsIGFscGhhID0gMCkNCg0KIyBPcHRpbWFsIGxhbWJkYQ0KbGFtYmRhX3JpZGdlIDwtIGN2X3JpZGdlJGxhbWJkYS5taW4NCg0KIyBSZWZpdCB0aGUgbW9kZWwgd2l0aCB0aGUgb3B0aW1hbCBsYW1iZGENCnJpZGdlX21vZGVsX29wdCA8LSBnbG1uZXQoWF90cmFpbiwgeV90cmFpbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBsYW1iZGFfcmlkZ2UpDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgRml0IEVsYXN0aWMgTmV0IG1vZGVsIChlLmcuLCBhbHBoYSA9IDAuNSkNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQplbGFzdGljX21vZGVsIDwtIGdsbW5ldChYX3RyYWluLCB5X3RyYWluLCBmYW1pbHkgPSAiYmlub21pYWwiLCBhbHBoYSA9IDAuNSkNCg0KIyBDcm9zcy12YWxpZGF0aW9uIHRvIGZpbmQgdGhlIG9wdGltYWwgbGFtYmRhDQpjdl9lbGFzdGljIDwtIGN2LmdsbW5ldChYX3RyYWluLCB5X3RyYWluLCBmYW1pbHkgPSAiYmlub21pYWwiLCBhbHBoYSA9IDAuNSkNCg0KIyBPcHRpbWFsIGxhbWJkYQ0KbGFtYmRhX2VsYXN0aWMgPC0gY3ZfZWxhc3RpYyRsYW1iZGEubWluDQoNCiMgUmVmaXQgdGhlIG1vZGVsIHdpdGggdGhlIG9wdGltYWwgbGFtYmRhDQplbGFzdGljX21vZGVsX29wdCA8LSBnbG1uZXQoWF90cmFpbiwgeV90cmFpbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSA9IGxhbWJkYV9lbGFzdGljKQ0KDQpgYGANCg0KYGBge3J9DQoNCmxhc3NvLmNvZWYgPC0gYXMubWF0cml4KGNvZWYobGFzc29fbW9kZWxfb3B0KSkNCnJpZGdlLmNvZWYgPC0gYXMubWF0cml4KGNvZWYocmlkZ2VfbW9kZWxfb3B0KSkNCmVsYXN0aWMuY29lZiA8LSBhcy5tYXRyaXgoY29lZihlbGFzdGljX21vZGVsX29wdCkpDQpyZWd1bGFyaXplZC5jb2VmIDwtIGRhdGEuZnJhbWUobGFzc28gPSBsYXNzby5jb2VmWywxXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWRnZSA9IHJpZGdlLmNvZWZbLDFdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBlbGFzdGljbmV0ID0gZWxhc3RpYy5jb2VmWywxXSkNCnBhbmRlcihyZWd1bGFyaXplZC5jb2VmKQ0KDQpgYGANCg0KIyMgT3B0aW1hbCBDdXR0b2ZmIFByb2JhYmlsaXR5IERldGVybWluYXRpb24NCg0KT3B0aW1hbCBDdXRvZmYgUHJvYmFiaWxpdHkgZm9yIHRoaXMgbW9kZWwgaXMgMCBmb3IgdGhlIHJlYXNvbnMgYmVsb3c6DQoNCkNsYXNzIEltYmFsYW5jZTogQSBoaWdobHkgaW1iYWxhbmNlZCBkYXRhc2V0IG1heSBjYXVzZSB0aGUgbW9kZWwgdG8gZmF2b3IgdGhlIG1ham9yaXR5IGNsYXNzLCBsZWFkaW5nIHRvIGFuIG9wdGltYWwgY3V0LW9mZiBvZiAwIGZvciBtYXhpbXVtIGFjY3VyYWN5Lg0KDQpPdmVyLVJlZ3VsYXJpemF0aW9uOiBTdHJvbmcgcmVndWxhcml6YXRpb24gKGhpZ2ggbGFtYmRhIHZhbHVlcykgY2FuIHNocmluayBjb2VmZmljaWVudHMsIHJlZHVjaW5nIHRoZSBtb2RlbOKAmXMgYWJpbGl0eSB0byBkaWZmZXJlbnRpYXRlIGJldHdlZW4gY2xhc3Nlcy4NCg0KQmlhcyBpbiBQcm9iYWJpbGl0eSBFc3RpbWF0ZXM6IElmIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIGFyZSBza2V3ZWQgdG93YXJkIGhpZ2hlciB2YWx1ZXMsIHRoZSBtb2RlbCBtYXkgY2xhc3NpZnkgbW9zdCBpbnN0YW5jZXMgYXMgdGhlIHBvc2l0aXZlIGNsYXNzLCBtYWtpbmcgMCB0aGUgYmVzdCBjdXQtb2ZmLg0KDQpBY2N1cmFjeSBhcyBhIE1pc2xlYWRpbmcgTWV0cmljOiBTaW5jZSBhY2N1cmFjeSBkb2VzIG5vdCBhY2NvdW50IGZvciBjbGFzcyBkaXN0cmlidXRpb24sIGFsdGVybmF0aXZlIG1ldHJpY3Mgc3VjaCBhcyBBVUMtUk9DLCBwcmVjaXNpb24tcmVjYWxsLCBhbmQgRjEtc2NvcmUgc2hvdWxkIGJlIGNvbnNpZGVyZWQgZm9yIGJldHRlciB0aHJlc2hvbGQgc2VsZWN0aW9uLg0KDQpgYGB7cn0NCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBQcmVkaWN0IG9uIHRoZSB0ZXN0IHNldDogdHlwZSA9ICJjbGFzcyIgdXNlcyB0aGUgZGVmYXVsdCANCiMgY3V0LW9mZiBwcm9iYWJpbGl0eSB0byBiZSAwLjUuDQpwcmVkaWN0X2xhc3NvIDwtIHByZWRpY3QobGFzc29fbW9kZWxfb3B0LCBuZXd4ID0gWF90ZXN0LCB0eXBlID0gInJlc3BvbnNlIikNCnByZWRpY3RfcmlkZ2UgPC0gcHJlZGljdChyaWRnZV9tb2RlbF9vcHQsIG5ld3ggPSBYX3Rlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQ0KcHJlZGljdF9lbGFzdGljIDwtIHByZWRpY3QoZWxhc3RpY19tb2RlbF9vcHQsIG5ld3ggPSBYX3Rlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQ0KDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIE9wdGltYWwgY3V0b2ZmIHByb2JhYmlsaXR5IGRldGVybWluYXRpb24NCnNlcS5jdXQgPC0gc2VxKDAsMSwgbGVuZ3RoPTUwKQ0KIyB5IGlzIGEgdmVjdG9yIG9mIDAgYW5kIDENCmFjYy5sYXNzbyA8LSBOVUxMDQphY2MucmlkZ2UgPC0gTlVMTA0KYWNjLmVsYXN0aWMgPC0gTlVMTA0KZm9yIChpIGluIDE6bGVuZ3RoKHNlcS5jdXQpKXsNCiAgIHByZWR5Lmxhc3NvIDwtIGlmZWxzZShwcmVkaWN0X2xhc3NvID5zZXEuY3V0W2ldLCAxLCAwKQ0KICAgcHJlZHkucmlkZ2U8LSBpZmVsc2UocHJlZGljdF9yaWRnZSA+c2VxLmN1dFtpXSwgMSwgMCkNCiAgIHByZWR5LmVsYXN0aWM8LSBpZmVsc2UocHJlZGljdF9lbGFzdGljID5zZXEuY3V0W2ldLCAxLCAwKQ0KICAgIyMNCiAgIGFjYy5sYXNzb1tpXSA8LSBtZWFuKHlfdGVzdCAgPT0gcHJlZHkubGFzc28pDQogICBhY2MucmlkZ2VbaV0gPC0gbWVhbih5X3Rlc3QgPT0gcHJlZHkucmlkZ2UpDQogICBhY2MuZWxhc3RpY1tpXSA8LSBtZWFuKHlfdGVzdCAgPT0gcHJlZHkuZWxhc3RpYykNCn0NCiMjIG9wdGltYWwgY3V0LW9mZjogaWYgdGhlIG1heGltdW0gYWNjdXJhY3kgb2NjdXJzIGF0IG11bHRpcGxlDQojIyBjdXQtb2ZmIHByb2JhYmlsaXRpZXMsIHRoZSBhdmVyYWdlIG9mIHRoZXNlIGN1dG9mZiBwcm9iYWJpbGl0aWVzDQojIyB3aWxsIGJlIGRlZmluZWQgYXMgdGhlIG9wdGltYWwgY3V0b2ZmIHByb2JhYmlsaXR5DQpvcHQuY3V0Lmxhc3NvIDwtIG1lYW4oc2VxLmN1dFt3aGljaChhY2MubGFzc289PW1heChhY2MubGFzc28pKV0pDQpvcHQuY3V0LnJpZGdlPC0gbWVhbihzZXEuY3V0W3doaWNoKGFjYy5yaWRnZT09bWF4KGFjYy5yaWRnZSkpXSkNCm9wdC5jdXQuZWxhc3RpYyA8LSBtZWFuKHNlcS5jdXRbd2hpY2goYWNjLmVsYXN0aWM9PW1heChhY2MuZWxhc3RpYykpXSkNCiMjDQoNCg0KDQojIFByaW50IG9wdGltYWwgY3V0b2ZmIHByb2JhYmlsaXRpZXMNCiNjYXQoIk9wdGltYWwgQ3V0b2ZmIGZvciBMQVNTTzoiLCBvcHQuY3V0Lmxhc3NvLCAiXG4iKQ0KI2NhdCgiT3B0aW1hbCBDdXRvZmYgZm9yIFJpZGdlOiIsIG9wdC5jdXQucmlkZ2UsICJcbiIpDQojY2F0KCJPcHRpbWFsIEN1dG9mZiBmb3IgRWxhc3RpYyBOZXQ6Iiwgb3B0LmN1dC5lbGFzdGljLCAiXG4iKQ0KDQphY2MuZGF0YSA8LSBkYXRhLmZyYW1lKHByb2IgPSByZXAoc2VxLmN1dCwzKSwgDQogICAgICAgICAgICAgICAgICAgICAgIGFjYz1jKGFjYy5sYXNzbywgYWNjLnJpZGdlLCBhY2MuZWxhc3RpYyksIA0KICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGMocmVwKCJsYXNzbyIsNTApLCByZXAoInJpZGdlIiw1MCksIHJlcCgiZWxhc3RpYyIsNTApKSkNCg0KYGBgDQoNCg0KIyMgQWNjdXJhY3kgUGxvdA0KDQpUaGUgYWNjdXJhY3kgdnMuIGN1dC1vZmYgcHJvYmFiaWxpdHkgcGxvdCBpbmRpY2F0ZXMgdGhhdCBhbGwgdGhyZWUgbW9kZWxz4oCUTEFTU08sIFJpZGdlLCBhbmQgRWxhc3RpYyBOZXTigJRleGhpYml0IG5lYXJseSBpZGVudGljYWwgY2xhc3NpZmljYXRpb24gcGVyZm9ybWFuY2UsIGFjaGlldmluZyBtYXhpbXVtIGFjY3VyYWN5ICh+MC43NTExKSBhdCBhIGxvdyBjdXQtb2ZmIHRocmVzaG9sZC4gQXMgdGhlIGN1dC1vZmYgaW5jcmVhc2VzLCBhY2N1cmFjeSBkZWNsaW5lcyBzaGFycGx5LCBzdWdnZXN0aW5nIGEgc3Ryb25nIGNsYXNzIGltYmFsYW5jZSBvciB0aHJlc2hvbGQgc2Vuc2l0aXZpdHkuIFRoZSBtb2RlbHMgcHJlZG9taW5hbnRseSBmYXZvciB0aGUgbWFqb3JpdHkgY2xhc3MgYXQgbG93ZXIgdGhyZXNob2xkcywgbGVhZGluZyB0byBoaWdoZXIgYWNjdXJhY3kgYnV0IHBvdGVudGlhbGx5IHBvb3Igc2Vuc2l0aXZpdHkgZm9yIG1pbm9yaXR5IGNsYXNzIGRldGVjdGlvbi4gVGhlIHJhcGlkIGRlY2xpbmUgaW4gYWNjdXJhY3kgYmV5b25kIGEgMC4xIGN1dC1vZmYgc3VnZ2VzdHMgdGhhdCBtaXNjbGFzc2lmaWNhdGlvbiByYXRlcyBpbmNyZWFzZSBzaWduaWZpY2FudGx5LiBUaGlzIGluZGljYXRlcyB0aGF0IGFjY3VyYWN5IGFsb25lIG1heSBub3QgYmUgdGhlIGJlc3QgZXZhbHVhdGlvbiBtZXRyaWMsIHdhcnJhbnRpbmcgYWRkaXRpb25hbCBhc3Nlc3NtZW50cyBzdWNoIGFzIEFVQy1ST0MgYW5kIEYxLXNjb3JlLiBPcHRpbWl6aW5nIHRoZSB0aHJlc2hvbGQgdXNpbmcgdGhlc2UgYWx0ZXJuYXRpdmUgbWV0cmljcyBjb3VsZCBlbmhhbmNlIHByZWRpY3RpdmUgcGVyZm9ybWFuY2UuDQoNCg0KYGBge3J9DQoNCiMjDQpnZy5hY2MgPC0gZ2dwbG90KGRhdGEgPSBhY2MuZGF0YSwgYWVzKHg9cHJvYiwgeSA9IGFjYywgY29sb3IgPSBncm91cCkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSAwLjYsIHkgPSAwLjQ1LCANCiAgICAgICAgICAgbGFiZWwgPSBwYXN0ZSggIkFjY3VyYWN5OiAiLCByb3VuZChtYXgoYWNjLmxhc3NvKSw1KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdXJhY3k6ICIsIHJvdW5kKG1heChhY2MucmlkZ2UpLDUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1cmFjeTogIiwgcm91bmQobWF4KGFjYy5lbGFzdGljKSw1KSksIA0KICAgICAgICAgICBzaXplID0gMywgDQogICAgICAgICAgIGNvbG9yID0gIm5hdnkiKSArDQogIGdndGl0bGUoIkN1dC1vZmYgUHJvYmFiaWxpdHkgdnMgQWNjdXJhY3kiKSArDQogIGxhYnMoeCA9ICJjdXQtb2ZmIFByb2JhYmlsaXR5IiwgDQogICAgICAgeSA9ICJhY2N1cmFjeSIsIGNvbG9yID0gIkdyb3VwIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KIyMNCmdncGxvdGx5KGdnLmFjYykNCg0KDQpgYGANCg0KDQoNCiMjIENvbmZ1c2lvbiBNYXRyaXgNCg0KVGhlIHBlcmZvcm1hbmNlIG1ldHJpY3MgZm9yIExBU1NPLCBSaWRnZSwgYW5kIEVsYXN0aWMgTmV0IHJlZ3Jlc3Npb24gbW9kZWxzIGluZGljYXRlIHN0cm9uZyByZWNhbGwgKDAuOTcwNCkgYWNyb3NzIGFsbCBtb2RlbHMsIHN1Z2dlc3RpbmcgdGhhdCB0aGV5IGVmZmVjdGl2ZWx5IGlkZW50aWZ5IHRoZSBwb3NpdGl2ZSBjbGFzcy4gSG93ZXZlciwgc3BlY2lmaWNpdHkgaXMgcmVsYXRpdmVseSBsb3cgKDAuMzkyOeKAkzAuMzc1KSwgbWVhbmluZyB0aGUgbW9kZWxzIHN0cnVnZ2xlIHRvIGNvcnJlY3RseSBjbGFzc2lmeSBuZWdhdGl2ZSBpbnN0YW5jZXMsIGxpa2VseSBkdWUgdG8gY2xhc3MgaW1iYWxhbmNlLiBQcmVjaXNpb24gdmFsdWVzICh+MC44MikgYW5kIEYxLXNjb3JlcyAofjAuODkpIGNvbmZpcm0gYSBnb29kIGJhbGFuY2UgYmV0d2VlbiBwcmVjaXNpb24gYW5kIHJlY2FsbCwgZmF2b3Jpbmcgc2Vuc2l0aXZpdHkuIFRoZSBiYWxhbmNlZCBhY2N1cmFjeSB2YWx1ZXMgKDAuNjgxNiBmb3IgTEFTU08sIDAuNjYzOCBmb3IgUmlkZ2UsIGFuZCAwLjY3MjcgZm9yIEVsYXN0aWMgTmV0KSBpbmRpY2F0ZSBtb2RlcmF0ZSBvdmVyYWxsIHBlcmZvcm1hbmNlLCB3aXRoIExBU1NPIHNsaWdodGx5IG91dHBlcmZvcm1pbmcgdGhlIG90aGVyIG1vZGVscy4gVGhlc2UgcmVzdWx0cyBzdWdnZXN0IHRoYXQgd2hpbGUgdGhlIG1vZGVscyBhcmUgc3Ryb25nIGluIGRldGVjdGluZyBwb3NpdGl2ZXMsIGZ1cnRoZXIgdGhyZXNob2xkIHR1bmluZyBvciBhbHRlcm5hdGl2ZSBldmFsdWF0aW9uIG1ldHJpY3MgKHN1Y2ggYXMgQVVDLVJPQykgbWF5IGltcHJvdmUgY2xhc3NpZmljYXRpb24gb2YgbmVnYXRpdmUgY2FzZXMuDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIyB1c2luZyB0aGUgb3B0aW1hbCBjdXRvZmYgcHJvYmFiaWxpdHkgdG8gcHJlZGljdCBsYWJlbHMNCiMjIA0KI3ByZWQubGFiLmxhc3NvIDwtIGlmZWxzZShwcmVkaWN0X2xhc3NvID5vcHQuY3V0Lmxhc3NvLCAxLCAwKQ0KI3ByZWQubGFiLnJpZGdlPC0gaWZlbHNlKHByZWRpY3RfcmlkZ2UgPm9wdC5jdXQucmlkZ2UsIDEsIDApDQojcHJlZC5sYWIuZWxhc3RpYzwtIGlmZWxzZShwcmVkaWN0X2VsYXN0aWMgPm9wdC5jdXQuZWxhc3RpYywgMSwgMCkNCg0KDQpuZXdfdGhyZXNob2xkIDwtIDAuNSAgIyBUcnkgYWRqdXN0aW5nIHRoaXMNCnByZWQubGFiLmxhc3NvIDwtIGlmZWxzZShwcmVkaWN0X2xhc3NvID4gbmV3X3RocmVzaG9sZCwgMSwgMCkNCnByZWQubGFiLnJpZGdlPC0gaWZlbHNlKHByZWRpY3RfcmlkZ2UgPm5ld190aHJlc2hvbGQsIDEsIDApDQpwcmVkLmxhYi5lbGFzdGljPC0gaWZlbHNlKHByZWRpY3RfZWxhc3RpYyA+bmV3X3RocmVzaG9sZCwgMSwgMCkNCg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgQ29udmVydCBwcmVkaWN0aW9ucyB0byBmYWN0b3JzDQpwcmVkLmxhYi5sYXNzby5mY3QgPC0gYXMuZmFjdG9yKHByZWQubGFiLmxhc3NvKQ0KcHJlZC5sYWIucmlkZ2UuZmN0IDwtIGFzLmZhY3RvcihwcmVkLmxhYi5yaWRnZSkNCnByZWQubGFiLmVsYXN0aWMuZmN0IDwtIGFzLmZhY3RvcihwcmVkLmxhYi5lbGFzdGljKQ0KeV90ZXN0IDwtIGZhY3RvcihpZmVsc2UoeV90ZXN0ID09IDIsIDEsIDApLCBsZXZlbHMgPSBjKDAsIDEpKQ0KDQojdGFibGUocHJlZC5sYWIubGFzc28uZmN0KQ0KI3RhYmxlKHlfdGVzdCkNCg0KIyBDb25mdXNpb24gTWF0cml4IGFuZCBNZXRyaWNzDQpjb25mdXNpb24ubGFzc28gPC0gY29uZnVzaW9uTWF0cml4KHByZWQubGFiLmxhc3NvLmZjdCwgeV90ZXN0KQ0KY29uZnVzaW9uLnJpZGdlPC0gY29uZnVzaW9uTWF0cml4KHByZWQubGFiLnJpZGdlLmZjdCwgeV90ZXN0KQ0KY29uZnVzaW9uLmVsYXN0aWMgPC0gY29uZnVzaW9uTWF0cml4KHByZWQubGFiLmVsYXN0aWMuZmN0LCB5X3Rlc3QpDQoNCiMjIENvbW1vbmx5IHVzZWQgcGVyZm9ybWFuY2UgbWVhc3VyZWQNClBlcmZNZWFzdXJlcyA8LSBjYmluZChsYXNzbyA9IGNvbmZ1c2lvbi5sYXNzbyRieUNsYXNzLCANCiAgICAgICAgICAgICAgICAgICAgIHJpZGdlID0gY29uZnVzaW9uLnJpZGdlJGJ5Q2xhc3MsIA0KICAgICAgICAgICAgICAgICAgICAgZWxhc3RpYyA9IGNvbmZ1c2lvbi5lbGFzdGljJGJ5Q2xhc3MpDQpwYW5kZXIoUGVyZk1lYXN1cmVzKQ0KDQoNCmBgYA0KDQoNCiMjIFJPQyBBbmFseXNpcw0KDQoNClRoZSBST0MgY3VydmUgY29tcGFyZXMgdGhlIHBlcmZvcm1hbmNlIG9mIHRocmVlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxz4oCUTEFTU08sIFJpZGdlLCBhbmQgRWxhc3RpYyBOZXTigJRiYXNlZCBvbiB0aGVpciBhYmlsaXR5IHRvIGRpc3Rpbmd1aXNoIGJldHdlZW4gY2xhc3Nlcy4gVGhlIGFyZWEgdW5kZXIgdGhlIGN1cnZlIChBVUMpIHZhbHVlcyBpbmRpY2F0ZSB0aGF0IGFsbCB0aHJlZSBtb2RlbHMgcGVyZm9ybSBzaW1pbGFybHksIHdpdGggRWxhc3RpYyBOZXQgYWNoaWV2aW5nIHRoZSBoaWdoZXN0IEFVQyAoMC44NDEpLCBmb2xsb3dlZCBjbG9zZWx5IGJ5IExBU1NPICgwLjg0KSBhbmQgUmlkZ2UgKDAuODM4KS4gVGhlc2UgdmFsdWVzIHN1Z2dlc3QgdGhhdCB0aGUgbW9kZWxzIGhhdmUgZ29vZCBwcmVkaWN0aXZlIGNhcGFiaWxpdGllcywgd2l0aCBFbGFzdGljIE5ldCBzbGlnaHRseSBvdXRwZXJmb3JtaW5nIHRoZSBvdGhlcnMgaW4gdGVybXMgb2YgY2xhc3NpZmljYXRpb24gYWNjdXJhY3kuDQoNCmBgYHtyfQ0KDQojIGxpYnJhcnkocFJPQykNCiMgUHJlZGljdGVkIHByb2JhYmlsaXRpZXMgZm9yIGVhY2ggbW9kZWw6IHR5cGUgPSAicmVzcG9uc2UiDQpwcm9iX2xhc3NvIDwtIHByZWRpY3QobGFzc29fbW9kZWxfb3B0LCBuZXd4ID0gWF90ZXN0LCB0eXBlID0gInJlc3BvbnNlIikNCnByb2JfcmlkZ2UgPC0gcHJlZGljdChyaWRnZV9tb2RlbF9vcHQsIG5ld3ggPSBYX3Rlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQ0KcHJvYl9lbGFzdGljIDwtIHByZWRpY3QoZWxhc3RpY19tb2RlbF9vcHQsIG5ld3ggPSBYX3Rlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQ0KDQojIENvbXB1dGUgUk9DIGN1cnZlczogcm9jIG9iamVjdCBjb250YWlucyBhIGxvdCBpbmZvcm1hdGlvbiBpbmNsdWRpbmcNCiMgc2Vuc2l0aXZpdHksIHNwZWNpZmljaXR5LCBBVUMsIGV0Yy4NCnJvY19sYXNzbyA8LSByb2MoeV90ZXN0LCBwcm9iX2xhc3NvKQ0Kcm9jX3JpZGdlIDwtIHJvYyh5X3Rlc3QsIHByb2JfcmlkZ2UpDQpyb2NfZWxhc3RpYyA8LSByb2MoeV90ZXN0LCBwcm9iX2VsYXN0aWMpDQoNCiMgQ29tcHV0ZSBBVUMgdmFsdWVzDQphdWNfbGFzc28gPC0gYXVjKHJvY19sYXNzbykNCmF1Y19yaWRnZSA8LSBhdWMocm9jX3JpZGdlKQ0KYXVjX2VsYXN0aWMgPC0gYXVjKHJvY19lbGFzdGljKQ0KDQojIyBMQVNTTw0Kc2VuLmxhc3NvIDwtIHJvY19sYXNzbyRzZW5zaXRpdml0aWVzDQpzcGUubGFzc28gPC0gcm9jX2xhc3NvJHNwZWNpZmljaXRpZXMNCmF1Yy5sYXNzbyA8LSByb2NfbGFzc28kYXVjDQoNCiMjIFJpZGdlDQpzZW4ucmlkZ2UgPC0gcm9jX3JpZGdlJHNlbnNpdGl2aXRpZXMNCnNwZS5yaWRnZSA8LSByb2NfcmlkZ2Ukc3BlY2lmaWNpdGllcw0KYXVjLnJpZGdlIDwtIHJvY19yaWRnZSRhdWMNCg0KIyMgRWxhc3RpYyBOZXQNCnNlbi5lbGFzdGljIDwtIHJvY19lbGFzdGljJHNlbnNpdGl2aXRpZXMNCnNwZS5lbGFzdGljIDwtIHJvY19lbGFzdGljJHNwZWNpZmljaXRpZXMNCmF1Yy5lbGFzdGljIDwtIHJvY19lbGFzdGljJGF1Yw0KDQojIyBQbG90dGluZyB0aGUgUk9DIGN1cnZlczogdGhyZWUgY29sb3JzIC0gZ3JlZW4sIG9yYW5nZSwgYW5kIHB1cnBsZQ0KDQpwbG90KDEtc3BlLmxhc3NvLCBzZW4ubGFzc28sIA0KICAgICB0eXBlID0gImwiLA0KICAgICBjb2wgPSAiZ3JlZW4iLCANCiAgICAgeGxpbT1jKDAsMSksDQogICAgIHhsYWIgPSAiMSAtIHNwZWNpZmljaXR5IiwNCiAgICAgeWxhYiA9ICJzZW5zaXRpdml0eSIsDQogICAgIG1haW4gPSAiUk9DIEN1cnZlcyBmb3IgTEFTU08sIFJpZGdlLCBhbmQgRWxhc3RpYyBOZXQiKQ0KbGluZXMoMS1zcGUucmlkZ2UsIHNlbi5yaWRnZSwgY29sID0gIm9yYW5nZSIpDQpsaW5lcygxLXNwZS5lbGFzdGljLCBzZW4uZWxhc3RpYywgY29sID0gInB1cnBsZSIpDQphYmxpbmUoMCwxLCB0eXBlID0gImwiLCBsdHkgPSAyLCBjb2wgPSAic3RlZWxibHVlIiwgbHdkID0gMSkNCg0KIyBBZGQgbGVnZW5kDQpsZWdlbmQoImJvdHRvbXJpZ2h0IiwgbGVnZW5kID0gYyhwYXN0ZSgiTEFTU08gKEFVQyA9Iiwgcm91bmQoYXVjX2xhc3NvLCAzKSwgIikiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlJpZGdlIChBVUMgPSIsIHJvdW5kKGF1Y19yaWRnZSwgMyksICIpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJFbGFzdGljIE5ldCAoQVVDID0iLCByb3VuZChhdWNfZWxhc3RpYywgMyksICIpIikpLA0KICAgICAgIGNvbCA9IGMoImdyZWVuIiwgIm9yYW5nZSIsICJwdXJwbGUiKSwgbHR5ID0gMSwgY2V4ID0gMC44LCBidHkgPSAibiIpDQoNCmBgYA0KDQojIyBTdXBwb3J0IFZlY3RvciBNYWNoaW5lIGZvciBDbGFzc2lmaWNhdGlvbg0KDQpUaGUgcmVzdWx0cyByZXByZXNlbnQgYSBjb25mdXNpb24gbWF0cml4IGZyb20gYSBTdXBwb3J0IFZlY3RvciBNYWNoaW5lIChTVk0pIGNsYXNzaWZpY2F0aW9uIG1vZGVsLCB3aGVyZTogIA0KDQotICoqMjA2KiogdHJ1ZSBuZWdhdGl2ZXMgKGNvcnJlY3RseSBjbGFzc2lmaWVkIGFzIGNsYXNzIDApICANCi0gKioxNCoqIGZhbHNlIHBvc2l0aXZlcyAobWlzY2xhc3NpZmllZCBhcyBjbGFzcyAxIGJ1dCBhY3R1YWxseSBjbGFzcyAwKSAgDQotICoqNTgqKiBmYWxzZSBuZWdhdGl2ZXMgKG1pc2NsYXNzaWZpZWQgYXMgY2xhc3MgMCBidXQgYWN0dWFsbHkgY2xhc3MgMSkgIA0KLSAqKjYxKiogdHJ1ZSBwb3NpdGl2ZXMgKGNvcnJlY3RseSBjbGFzc2lmaWVkIGFzIGNsYXNzIDEpICANCg0KIyMjICoqQW5hbHlzaXM6KiogIA0KMS4gKipBY2N1cmFjeSoqOiAgVGhlIG1vZGVsIGFjaGlldmVzIGFuIGFjY3VyYWN5IG9mIGFwcHJveGltYXRlbHkgKio3OC43NiUqKi4NCg0KMi4gKipQcmVjaXNpb24gKFBvc2l0aXZlIFByZWRpY3RpdmUgVmFsdWUpKiogZm9yIENsYXNzIDE6IFdoZW4gdGhlIG1vZGVsIHByZWRpY3RzIGNsYXNzIDEsIGl0IGlzIGNvcnJlY3QgYWJvdXQgKio4MS4zMyUqKiBvZiB0aGUgdGltZS4NCg0KMy4gKipSZWNhbGwgKFNlbnNpdGl2aXR5IG9yIFRydWUgUG9zaXRpdmUgUmF0ZSkqKiBmb3IgQ2xhc3MgMTogVGhlIG1vZGVsIGNvcnJlY3RseSBpZGVudGlmaWVzICoqNTEuMjYlKiogb2YgYWN0dWFsIGNsYXNzIDEgaW5zdGFuY2VzLCBpbmRpY2F0aW5nIHRoYXQgaXQgbWlzc2VzIGEgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIHBvc2l0aXZlcy4NCg0KNC4gKipTcGVjaWZpY2l0eSAoVHJ1ZSBOZWdhdGl2ZSBSYXRlKSoqOiBUaGUgbW9kZWwgY29ycmVjdGx5IGlkZW50aWZpZXMgKio5My42MyUqKiBvZiBhY3R1YWwgY2xhc3MgMCBpbnN0YW5jZXMsIHNob3dpbmcgc3Ryb25nIHBlcmZvcm1hbmNlIGluIHJlY29nbml6aW5nIG5lZ2F0aXZlcy4NCg0KNS4gKipPcHRpbWFsIEN1dG9mZjoqKiAqKjAuMTc0MioqICANCiAgIC0gVGhlIGNsYXNzaWZpY2F0aW9uIHRocmVzaG9sZCAoY3V0b2ZmKSB3YXMgb3B0aW1pemVkIHRvICoqMC4xNzQyKiosIG1lYW5pbmcgdGhhdCBhbnkgcHJlZGljdGVkIHByb2JhYmlsaXR5IGFib3ZlIHRoaXMgaXMgY2xhc3NpZmllZCBhcyBjbGFzcyAxLiAgDQogICAtIEEgbG93IHRocmVzaG9sZCBsaWtlIHRoaXMgc3VnZ2VzdHMgdGhlIG1vZGVsIGlzIGRlc2lnbmVkIHRvIGJlIG1vcmUgc2Vuc2l0aXZlIHRvIGRldGVjdGluZyBjbGFzcyAxLCBsaWtlbHkgdG8gcmVkdWNlIGZhbHNlIG5lZ2F0aXZlcy4gSG93ZXZlciwgdGhpcyBhbHNvIGluY3JlYXNlcyB0aGUgZmFsc2UgcG9zaXRpdmUgcmF0ZS4NCg0KIA0KVGhlIFNWTSBjbGFzc2lmaWVyIHBlcmZvcm1zIHdlbGwgaW4gaWRlbnRpZnlpbmcgY2xhc3MgMCAoaGlnaCBzcGVjaWZpY2l0eSkgYnV0IHN0cnVnZ2xlcyB3aXRoIGNsYXNzIDEgKGxvdyByZWNhbGwpLiBUaGUgb3B0aW1hbCB0aHJlc2hvbGQgKDAuMTc0Mikgd2FzIGNob3NlbiB0byBiYWxhbmNlIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSwgYnV0IHRoZSByZWNhbGwgZm9yIGNsYXNzIDEgcmVtYWlucyByZWxhdGl2ZWx5IGxvdy4gSWYgbWlzY2xhc3NpZnlpbmcgY2xhc3MgMSBpcyBjb3N0bHksIGFkanVzdGluZyB0aGUgdGhyZXNob2xkIG9yIG1vZGVsIHR1bmluZyAoZS5nLiwgY2hhbmdpbmcga2VybmVsIGZ1bmN0aW9ucywgcmVndWxhcml6YXRpb24gcGFyYW1ldGVycykgbWF5IGltcHJvdmUgcmVjYWxsLg0KDQoNCmBgYHtyfQ0KDQoNCiMgTG9hZCB0aGUgZGF0YXNldA0KDQpkZiRCYW5rcnVwdCA8LSBhcy5mYWN0b3IoZGYkQmFua3J1cHQpDQoNCiMgVHJhaW4tdGVzdCBzcGxpdA0Kc2V0LnNlZWQoMTIzKQ0KaW5kZXggPC0gc2FtcGxlKDE6bnJvdyhkZiksIDAuNyAqIG5yb3coZGYpKQ0KdHJhaW4uZGF0YSA8LSBkZltpbmRleCwgXQ0KdGVzdC5kYXRhIDwtIGRmWy1pbmRleCwgXQ0KDQojIFNldCB1cCBjdXN0b20gY3Jvc3MtdmFsaWRhdGlvbiBjb250cm9sDQp0dW5lX2NvbnRyb2wgPC0gdHVuZS5jb250cm9sKGNyb3NzID0gNSwgbnJlcGVhdCA9IDEpDQoNCiMgUGVyZm9ybSBhIGdyaWQgc2VhcmNoIGZvciB0aGUgYmVzdCBoeXBlcnBhcmFtZXRlcnMNCnR1bmUuUkJGIDwtIHR1bmUoDQogIHN2bSwNCiAgQmFua3J1cHQgfiAuLA0KICBkYXRhID0gdHJhaW4uZGF0YSwNCiAga2VybmVsID0gInJhZGlhbCIsDQogIHJhbmdlcyA9IGxpc3QoY29zdCA9IDEwXigtMToyKSwgZ2FtbWEgPSBjKDAuMSwgMC41LCAxLCAyKSksDQogIHR1bmVjb250cm9sID0gdHVuZV9jb250cm9sDQopDQoNCiMgRXh0cmFjdCB0aGUgYmVzdCBtb2RlbA0KYmVzdC5SQkYgPC0gdHVuZS5SQkYkYmVzdC5tb2RlbA0KDQojIFRyYWluIGZpbmFsIG1vZGVsIHdpdGggcHJvYmFiaWxpdHkgZXN0aW1hdGlvbg0KdHVuZWQuc3ZtIDwtIHN2bSgNCiAgQmFua3J1cHQgfiAuLA0KICBkYXRhID0gdHJhaW4uZGF0YSwNCiAga2VybmVsID0gInJhZGlhbCIsDQogIGNvc3QgPSBiZXN0LlJCRiRjb3N0LA0KICBnYW1tYSA9IGJlc3QuUkJGJGdhbW1hLA0KICBwcm9iYWJpbGl0eSA9IFRSVUUNCikNCg0KIyBQcmVkaWN0IHByb2JhYmlsaXRpZXMNCnByZWQucHJvYnMgPC0gcHJlZGljdCh0dW5lZC5zdm0sIHRlc3QuZGF0YSwgcHJvYmFiaWxpdHkgPSBUUlVFKQ0KcHJlZC5wcm9icyA8LSBhdHRyKHByZWQucHJvYnMsICJwcm9iYWJpbGl0aWVzIilbLCAyXSAgIyBFeHRyYWN0IHByb2JhYmlsaXRpZXMgZm9yIGNsYXNzICIxIg0KDQojIENvbXB1dGUgb3B0aW1hbCBjdXRvZmYgYnkgbWluaW1pemluZyBkaXN0YW5jZSB0byAoMCwxKSBpbiBST0Mgc3BhY2UNCnByZWQgPC0gcHJlZGljdGlvbihwcmVkLnByb2JzLCB0ZXN0LmRhdGEkQmFua3J1cHQpDQpwZXJmIDwtIHBlcmZvcm1hbmNlKHByZWQsICJ0cHIiLCAiZnByIikNCg0KY3V0b2ZmcyA8LSBkYXRhLmZyYW1lKA0KICBjdXRvZmYgPSBwZXJmQGFscGhhLnZhbHVlc1tbMV1dLA0KICB0cHIgPSBwZXJmQHkudmFsdWVzW1sxXV0sDQogIGZwciA9IHBlcmZAeC52YWx1ZXNbWzFdXQ0KKQ0KY3V0b2ZmcyRkaXN0YW5jZSA8LSBzcXJ0KCgxIC0gY3V0b2ZmcyR0cHIpXjIgKyBjdXRvZmZzJGZwcl4yKQ0Kb3B0aW1hbC5jdXRvZmYgPC0gY3V0b2ZmcyRjdXRvZmZbd2hpY2gubWluKGN1dG9mZnMkZGlzdGFuY2UpXQ0KDQojIEFwcGx5IG9wdGltYWwgY3V0b2ZmDQpwcmVkLm9wdGltYWwuY2xhc3MgPC0gaWZlbHNlKHByZWQucHJvYnMgPiBvcHRpbWFsLmN1dG9mZiwgMSwgMCkNCg0KIyBDb25mdXNpb24gbWF0cml4IHdpdGggb3B0aW1hbCBjdXRvZmYNCmNvbmZ1c2lvbi5tYXRyaXgub3B0aW1hbCA8LSB0YWJsZShQcmVkaWN0ZWQgPSBwcmVkLm9wdGltYWwuY2xhc3MsIEFjdHVhbCA9IHRlc3QuZGF0YSRCYW5rcnVwdCkNCnByaW50KGNvbmZ1c2lvbi5tYXRyaXgub3B0aW1hbCkNCg0KDQoNCiMgUHJpbnQgb3B0aW1hbCBjdXRvZmYgdmFsdWUNCnByaW50KHBhc3RlKCJPcHRpbWFsIEN1dG9mZjogIiwgb3B0aW1hbC5jdXRvZmYpKQ0KDQoNCg0KYGBgDQoNCg0KDQojIyBBY2N1cmFjeQ0KDQoNCmBgYHtyfQ0KDQojIENhbGN1bGF0ZSBhY2N1cmFjeQ0KYWNjdXJhY3kgPC0gc3VtKGRpYWcoY29uZnVzaW9uLm1hdHJpeC5vcHRpbWFsKSkgLyBzdW0oY29uZnVzaW9uLm1hdHJpeC5vcHRpbWFsKQ0KY2F0KCJcblxuIEFjY3VyYWN5OiIsIGFjY3VyYWN5LCAiXG4iKQ0KDQpgYGANCg0KDQoNCg0KDQoNCg0KIyMgUk9DDQoNClRoZSBST0MgY3VydmUgY29tcGFyZXMgdGhlIGNsYXNzaWZpY2F0aW9uIHBlcmZvcm1hbmNlIG9mIHRocmVlIG1vZGVsczogU3VwcG9ydCBWZWN0b3IgTWFjaGluZSAoU1ZNKSB3aXRoIGEgbGluZWFyIGtlcm5lbCwgU1ZNIHdpdGggYSByYWRpYWwga2VybmVsLCBhbmQgbG9naXN0aWMgcmVncmVzc2lvbi4gVGhlIEFyZWEgVW5kZXIgdGhlIEN1cnZlIChBVUMpIHZhbHVlcyBpbmRpY2F0ZSB0aGF0IHRoZSByYWRpYWwga2VybmVsIFNWTSBhY2hpZXZlcyB0aGUgYmVzdCBwZXJmb3JtYW5jZSAoQVVDID0gMC44NzU2KSwgZm9sbG93ZWQgYnkgdGhlIGxpbmVhciBrZXJuZWwgU1ZNIChBVUMgPSAwLjg0OTMpLCBhbmQgbG9naXN0aWMgcmVncmVzc2lvbiAoQVVDID0gMC44MzE5KS4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZSByYWRpYWwga2VybmVsIFNWTSBwcm92aWRlcyB0aGUgaGlnaGVzdCBkaXNjcmltaW5hdG9yeSBwb3dlciBpbiBkaXN0aW5ndWlzaGluZyBiZXR3ZWVuIGNsYXNzZXMsIG1ha2luZyBpdCB0aGUgbW9zdCBlZmZlY3RpdmUgbW9kZWwgZm9yIHRoaXMgY2xhc3NpZmljYXRpb24gdGFzay4NCg0KYGBge3J9DQoNCg0KIyMNCiMjIFNldCB1cCBjdXN0b20gY3Jvc3MtdmFsaWRhdGlvbiBjb250cm9sDQp0dW5lLmNvbnRyb2wgPC0gdHVuZS5jb250cm9sKA0KICBjcm9zcyA9IDUsICAjIFVzZSA1LWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiwgdGhlIGRlZmF1bHQgaXMgMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uDQogIG5yZXBlYXQgPSAxICMgTnVtYmVyIG9mIHJlcGV0aXRpb25zIChmb3IgcmVwZWF0ZWQgY3Jvc3MtdmFsaWRhdGlvbikNCikNCiMjIA0KIyMgUGVyZm9ybSBhIGdyaWQgc2VhcmNoIGZvciB0aGUgYmVzdCBoeXBlcnBhcmFtZXRlcnMNCnR1bmUubGluIDwtIHR1bmUoDQogIHN2bSwgICAgICAgICAgIyB1c2luZyB0aGUgcHJpbWFyeSBzdm0oKSBhbGdvcml0aG0gdG8gdHVuZSBwYXJhbWV0ZXINCiAgQmFua3J1cHQgfiAuLCAjIG1vZGVsIGZvcm11bGENCiAgZGF0YSA9IHRyYWluLmRhdGEsDQogIGtlcm5lbCA9ICJsaW5lYXIiLCAgICAjIFlvdSBjYW4gY2hhbmdlIHRoZSBrZXJuZWwgaWYgbmVlZGVkDQogIHJhbmdlcyA9IGxpc3QoDQogICAgY29zdCA9IDEwXigtMToyKSAgICMgdHVuZSB0aGUgaHlwZXJwYXJhbWV0ZXIgQyBpbiB0aGUgbG9zcyBmdW5jdGlvbg0KICApLA0KICB0dW5lY29udHJvbCA9IHR1bmUuY29udHJvbCAgIyBVc2UgY3VzdG9tIGNyb3NzLXZhbGlkYXRpb24gc2V0dGluZ3MNCikNCiMgUHJpbnQgdGhlIHR1bmluZyByZXN1bHRzIGZvciBpbnNwZWN0aW9uDQojIHByaW50KHR1bmVfcmVzdWx0KQ0KIyMNCiMjIEV4dHJhY3QgdGhlIGJlc3QgbW9kZWwgYW5kIGh5cGVycGFyYW1ldGVycw0KYmVzdC5saW4gPC0gdHVuZS5saW4kYmVzdC5tb2RlbA0KYmVzdC5jb3N0LmxpbiA8LSBiZXN0LmxpbiRjb3N0DQoNCnR1bmUuUkJGIDwtIHR1bmUoDQogIHN2bSwgDQogIEJhbmtydXB0IH4gLiwgDQogIGRhdGEgPSB0cmFpbi5kYXRhLA0KICBrZXJuZWwgPSAicmFkaWFsIiwNCiAgcmFuZ2VzID0gbGlzdCgNCiAgICBjb3N0ID0gMTBeKC0xOjIpLCAgIyBUdW5lIGNvc3QNCiAgICBnYW1tYSA9IDEwXigtMzoxKSAgIyBUdW5lIGdhbW1hDQogICksDQogIHR1bmVjb250cm9sID0gdHVuZS5jb250cm9sDQopDQoNCiMgRXh0cmFjdCBiZXN0IGh5cGVycGFyYW1ldGVycw0KYmVzdC5jb3N0LlJCRiA8LSB0dW5lLlJCRiRiZXN0Lm1vZGVsJGNvc3QNCmJlc3QuZ2FtbWEuUkJGIDwtIHR1bmUuUkJGJGJlc3QubW9kZWwkZ2FtbWENCg0KIyBQcmludCB0aGUgYmVzdCBoeXBlcnBhcmFtZXRlcnMgZm9yIGluc3BlY3Rpb24NCiMgY2F0KCJCZXN0IENvc3Q6IiwgYmVzdF9jb3N0LCAiXG4iKQ0KIyBjYXQoIkJlc3QgR2FtbWE6IiwgYmVzdF9nYW1tYSwgIlxuIikNCiMjDQojIyBUcmFpbiB0aGUgZmluYWwgU1ZNIG1vZGVsIHdpdGggdGhlIGJlc3QgaHlwZXJwYXJhbWV0ZXJzDQpmaW5hbC5saW4gPC0gc3ZtKA0KICBCYW5rcnVwdCB+IC4sDQogIGRhdGEgPSB0cmFpbi5kYXRhLA0KICBrZXJuZWwgPSAibGluZWFyIiwNCiAgY29zdCA9IGJlc3QuY29zdC5saW4sDQogIHByb2JhYmlsaXR5ID0gVFJVRQ0KKQ0KDQojIyBSZXF1ZXN0IHRvIHJldHVybiBwcm9iYWJpbGl0aWVzIGluIGZpbmFsLlJCRg0KDQpmaW5hbC5SQkYgPC0gc3ZtKA0KICBCYW5rcnVwdCB+IC4sDQogIGRhdGEgPSB0cmFpbi5kYXRhLA0KICBrZXJuZWwgPSAicmFkaWFsIiwNCiAgY29zdCA9IGJlc3QuY29zdC5SQkYsDQogIGdhbW1hID0gYmVzdC5nYW1tYS5SQkYsDQogIHByb2JhYmlsaXR5ID0gVFJVRQ0KKQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIyMgIGxvZ2lzdGljIHJlZ3Jlc3Npb24NCmxvZ2l0LmZpdCA8LSBnbG0oQmFua3J1cHQgfiAuLCBkYXRhID0gdHJhaW4uZGF0YSwgZmFtaWx5ID0gYmlub21pYWwpDQpBSUMubG9naXQgPC0gc3RlcChsb2dpdC5maXQsIGRpcmVjdGlvbiA9ICJib3RoIiwgdHJhY2UgPSAwKQ0KcHJlZC5sb2dpdCA8LSBwcmVkaWN0KEFJQy5sb2dpdCwgdGVzdC5kYXRhLCB0eXBlID0gInJlc3BvbnNlIikNCg0KIyMjDQojIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBST0MgQ3VydmUgYW5kIEFVQw0KcHJlZC5wcm9iLmxpbiA8LSBwcmVkaWN0KGZpbmFsLmxpbiwgdGVzdC5kYXRhLCBwcm9iYWJpbGl0eSA9IFRSVUUpDQpwcmVkLnByb2IuUkJGIDwtIHByZWRpY3QoZmluYWwuUkJGLCB0ZXN0LmRhdGEsIHByb2JhYmlsaXR5ID0gVFJVRSkNCiMjDQojIyBleHRyYWN0aW5nIHByb2JhYmlsaXRpZXMNCnByb2IubGluZWFyIDwtIGF0dHIocHJlZC5wcm9iLmxpbiwgInByb2JhYmlsaXRpZXMiKVssIDJdDQpwcm9iLnJhZGlhbCA8LSBhdHRyKHByZWQucHJvYi5SQkYsICJwcm9iYWJpbGl0aWVzIilbLCAyXQ0KIyMjDQpyb2NfbGluIDwtIHJvYyh0ZXN0LmRhdGEkQmFua3J1cHQsIHByb2IubGluZWFyKQ0Kcm9jX1JCRiA8LSByb2ModGVzdC5kYXRhJEJhbmtydXB0LCBwcm9iLnJhZGlhbCkNCnJvY19sb2dpdCA8LSByb2ModGVzdC5kYXRhJEJhbmtydXB0LCBwcmVkLmxvZ2l0KQ0KIyMjIFNlbi1TcGUNCmxpbi5zZW4gPC0gcm9jX2xpbiRzZW5zaXRpdml0aWVzDQpsaW4uc3BlIDwtIHJvY19saW4kc3BlY2lmaWNpdGllcw0KcmFkLnNlbiA8LSByb2NfUkJGJHNlbnNpdGl2aXRpZXMNCnJhZC5zcGUgPC0gcm9jX1JCRiRzcGVjaWZpY2l0aWVzDQpsb2dpdC5zZW4gPC0gcm9jX2xvZ2l0JHNlbnNpdGl2aXRpZXMNCmxvZ2l0LnNwZSA8LSByb2NfbG9naXQkc3BlY2lmaWNpdGllcw0KIyMgQVVDDQphdWMubGluIDwtIHJvY19saW4kYXVjDQphdWMucmFkIDwtIHJvY19SQkYkYXVjDQphdWMubG9naXQgPC0gcm9jX2xvZ2l0JGF1Yw0KIyMgUGxvdHRpbmcgUk9DIGN1cnZlcw0KDQpwbG90KDEtbGluLnNwZSwgbGluLnNlbiwgIA0KICAgICB4bGFiID0gIjEgLSBzcGVjaWZpY2l0eSIsDQogICAgIHlsYWIgPSAic2Vuc2l0aXZpdHkiLA0KICAgICBjb2wgPSAiZGFya3JlZCIsDQogICAgIHR5cGUgPSAibCIsDQogICAgIGx0eSA9IDEsDQogICAgIGx3ZCA9IDEsDQogICAgIG1haW4gPSAiUk9DIEN1cnZlcyBvZiBTVk0iKQ0KbGluZXMoMS1yYWQuc3BlLCByYWQuc2VuLCANCiAgICAgIGNvbCA9ICJibHVlIiwNCiAgICAgIGx0eSA9IDEsDQogICAgICBsd2QgPSAxKQ0KbGluZXMoMS1sb2dpdC5zcGUsIGxvZ2l0LnNlbiwgICAgICANCiAgICAgIGNvbCA9ICJvcmFuZ2UiLA0KICAgICAgbHR5ID0gMSwNCiAgICAgIGx3ZCA9IDEpDQphYmxpbmUoMCwxLCBjb2wgPSAic2t5Ymx1ZTMiLCBsdHkgPSAyLCBsd2QgPSAyKQ0KYWJsaW5lKHY9YygwLjA0OSwwLjE1MSksIGx0eSA9IDMsIGNvbCA9ICJkYXJrZ3JlZW4iKQ0KbGVnZW5kKCJib3R0b21yaWdodCIsIGMoIkxpbmVhciBLZXJuZWwiLCAiUmFkaWFsIEtlcm5lbCIsICJMb2dpc3RpYyBSZWdyZXNzaW9uIiksDQogICAgICAgbHR5ID0gYygxLDEsMSksIGx3ZCA9IHJlcCgxLDMpLA0KICAgICAgIGNvbCA9IGMoInJlZCIsICJibHVlIiwgIm9yYW5nZSIpLA0KICAgICAgIGJ0eT0ibiIsY2V4ID0gMC44KQ0KIyMgYW5ub3RhdGlvbiAtIEFVQw0KdGV4dCgwLjgsIDAuNDYsIHBhc3RlKCJMaW5lYXIgQVVDOiAiLCByb3VuZChhdWMubGluLDQpKSwgY2V4ID0gMC44KQ0KdGV4dCgwLjgsIDAuNCwgcGFzdGUoIlJhZGlhbCBBVUM6ICIsIHJvdW5kKGF1Yy5yYWQsNCkpLCBjZXggPSAwLjgpDQp0ZXh0KDAuOCwgMC4zNCwgcGFzdGUoIkxvZ2lzdGljIEFVQzogIiwgcm91bmQoYXVjLmxvZ2l0LDQpKSwgY2V4ID0gMC44KQ0KDQpgYGANCg0KDQojIyBNb2RlbCBDb21wYXJpc29uDQoNClJlZ3VsYXJpemVkIENsYXNzaWZpY2F0aW9uIHZzIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmUgQ2xhc3NpZmljYXRpb246DQoNClJlZ3VsYXJpemVkIGNsYXNzaWZpY2F0aW9uIChMYXNzbywgUmlkZ2UsIGFuZCBFbGFzdGljIE5ldCkgYW5kIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmUgKFNWTSkgY2xhc3NpZmljYXRpb24gZXhoaWJpdCBkaXN0aW5jdCBzdHJlbmd0aHMuIFJlZ3VsYXJpemVkIGNsYXNzaWZpY2F0aW9uIG1vZGVscyBkZW1vbnN0cmF0ZSBoaWdoIHNlbnNpdGl2aXR5ICg5Ny4wNCUpIGFjcm9zcyBhbGwgbWV0aG9kcywgbWVhbmluZyB0aGV5IGVmZmVjdGl2ZWx5IGNhcHR1cmUgcG9zaXRpdmUgY2FzZXMuIEhvd2V2ZXIsIHRoZWlyIHNwZWNpZmljaXR5IGlzIHJlbGF0aXZlbHkgbG93IChyYW5naW5nIGZyb20gMzUuNzElIHRvIDM5LjI5JSksIGluZGljYXRpbmcgdGhleSBzdHJ1Z2dsZSB3aXRoIGNvcnJlY3RseSBpZGVudGlmeWluZyBuZWdhdGl2ZXMuIEluIGNvbnRyYXN0LCB0aGUgU1ZNIGNsYXNzaWZpZXIgYWNoaWV2ZXMgbXVjaCBoaWdoZXIgc3BlY2lmaWNpdHkgKDkzLjYzJSksIG1lYW5pbmcgaXQgaXMgZXhjZWxsZW50IGF0IGlkZW50aWZ5aW5nIG5lZ2F0aXZlIGNhc2VzLCBidXQgaXRzIHNlbnNpdGl2aXR5IGlzIHNpZ25pZmljYW50bHkgbG93ZXIgKDUxLjI2JSksIGxlYWRpbmcgdG8gYSBoaWdoZXIgcmF0ZSBvZiBtaXNzZWQgcG9zaXRpdmUgY2FzZXMuIEFkZGl0aW9uYWxseSwgdGhlIFNWTSBtb2RlbCBoYXMgYW4gb3ZlcmFsbCBhY2N1cmFjeSBvZiA3OC43NiUsIGJhbGFuY2luZyBwcmVjaXNpb24gYW5kIHJlY2FsbCB3aXRoIGFuIG9wdGltaXplZCBjdXRvZmYgb2YgMC4xNzQyLiBVbHRpbWF0ZWx5LCByZWd1bGFyaXplZCBjbGFzc2lmaWNhdGlvbiBtb2RlbHMgYXJlIGJldHRlciBzdWl0ZWQgd2hlbiBjYXB0dXJpbmcgcG9zaXRpdmVzIGlzIGNyaXRpY2FsLCB3aGVyZWFzIFNWTSBpcyBwcmVmZXJhYmxlIHdoZW4gY29ycmVjdGx5IGlkZW50aWZ5aW5nIG5lZ2F0aXZlcyBpcyBhIHByaW9yaXR5Lg0KDQoNCg==